脚本:编写策略
策略脚本定义 decide(bars, params, ctx, state),每根收盘 K 线返回一个决策。该决策只驱动模拟评估账户,不会驱动其他任何东西。
Senzoukria · 文档 · 更新于 2026 年 9 月
位置
- 位置
- 脚本页面 → 新建策略
- 入口函数
- decide(bars, params, ctx, state),返回一个决策或 null
- 调用节奏
- 每根收盘 K 线一次——正在形成的 K 线永远不会传入
- 账户
- 本机的模拟评估账户;平台不会向任何经纪商发送订单
- 语言
- JavaScript 和 Python 共用同一个入口函数和同一种决策结构
它做什么
策略在与指标相同的沙箱中运行。系统会在你的代码之后追加一小段包装代码——之所以放在后面,是为了让行号与你在编辑器中看到的保持一致——它调用 decide()、规范化返回值,并把 state 对象传递到下一根 K 线。
如果没有定义 decide(),运行会失败并提示策略必须定义 decide(bars, params, ctx, state)。如果返回 undefined 或 null,这是一个有效答案,意思是「这根 K 线不交易」,运行状态条会显示「此样本上没有交易」。
上下文携带模拟持仓、是否空仓的标志和最小变动价位,因此距离以 tick 表示,同一个脚本换一个合约也无需改动。
决策对象
| 字段 | 默认值 | 它改变什么 |
|---|---|---|
| action: "buy" | — | 在模拟账户上以市价开多,受账户护栏约束。 |
| action: "sell" | — | 以市价开空,受同样的护栏约束。 |
| action: "close" | — | 平掉未平仓头寸;已经空仓时无害。 |
| qty | 1 | 手数。向下取整,且最小限制为 1。 |
| stopTicks | 无 | 以 tick 表示的止损离场距离,从成交价起算。 |
| targetTicks | 无 | 以 tick 表示的止盈离场距离。 |
| null | — | 这根 K 线不交易。 |
| state | {} | 你存进 state 对象的任何内容都会在下一根 K 线交还给你;脚本改动时会被清空。 |
怎么用
- 从 Breakout 策略模板开始:它在突破 N 根 K 线高点时买入,使用固定止损和止盈,并演示了如何用携带的 state 统计持仓已经过去多少根 K 线。
- 先在示例数据上运行——策略运行会报告究竟有没有返回决策,这是发现某个条件从未触发的最快办法。
- 然后把它挂到 Replay 的自动策略面板上,在真实回放数据上逐根 K 线观察它如何决策。
- 用 tick 而不是价格来表达风险:最小变动价位由上下文传入,账户会把距离换算成离场价位。
限制与陷阱
- 任何入场之前都会先检查账户护栏:突破回撤、触及当日亏损上限或超出手数上限都会被拒绝,面板会显示原因。
- 不属于已识别决策的返回值会被如实报告,并列出可接受的形态。
- 由于决策发生在收盘 K 线上,策略无法对 K 线内的行情作出反应——正是这一点让同一份代码的实时模拟运行与回测保持可比。
- 没有任何脚本能触及经纪商。这里的策略是纸上交易策略,它产生的任何结果都不是对实盘交易的承诺。
相关页面
其他语言版本
常见问题
- 策略可以用 Python 写吗?
- 可以。包装代码在每种语言中都有,并且按脚本的语言追加,所以 Python 策略得到的是 Python 包装。决策的键请写成 stopTicks 和 targetTicks:自动策略面板读的是这两个。Python 回测循环同时也接受 stop_ticks 和 target_ticks。
- 怎样在两根 K 线之间保留一个值?
- 把它写到第四个参数传入的 state 对象上。下一次调用时会交还给你,切换脚本时会被重置。
- 为什么我的买入被拒绝了?
- 要么是账户护栏拦住了它——原因会打印出来——要么是该品种没有可用的实时价格,这种情况下入场会等待,而不是凭空捏造一笔成交。