使用手册
功能在哪 · 是什么 · 怎么调出来一、PowerLanguage / EasyLanguage 是什么
1、两种语言的关系
- EasyLanguage:TradeStation 在 1980 年代发明的策略语言,类 Pascal 语法,接近英文口语
- PowerLanguage:MultiCharts 对 EasyLanguage 的高度兼容复刻,绝大多数代码可以直接复制过去用
- 两语言都是事件驱动 + 逐 Bar 计算:每根K线收盘时从头到尾把代码跑一遍
2、与其他策略语言的差别
| 语言 | 平台 | 语法风格 |
|---|---|---|
| EasyLanguage / PowerLanguage | TradeStation / MultiCharts | 类 Pascal,像写英文句子 |
| MQL4 / MQL5 | MT4 / MT5 | 类 C,逐笔事件驱动 |
| Pine Script | TradingView | 类 Python,序列化计算 |
白话注解:EasyLanguage 是"期货界的英语"。1980 年代 TradeStation 发明的,后来 MultiCharts 几乎一模一样地复刻过来。学一个,两个平台都能用。它最大的特点是"像人话"——Buy next bar at market; 翻译过来就是"下一根K线开盘市价买入",不需要学多少编程概念。
3、三种脚本类型
| 类型 | 用途 | 能不能自动下单 |
|---|---|---|
| Indicator(指标) | 画线、标记、报警 | 不能 |
| Signal(信号/策略) | 产生买卖信号,可回测可实盘 | 能 |
| Function(函数) | 可复用的计算模块 | — |
写自动交易,用的就是 Signal。
操作教程
一步一步 · 跟着做完一件事二、程序结构与声明顺序
1、官方要求的声明顺序
EasyLanguage 要求代码按固定顺序组织:
Inputs(参数声明)Variables(变量声明)- 变量赋值语句
Plot语句(仅指标用)- 买卖语句(仅策略用)
Inputs: FastLen(10); { 1. 参数 }
Variables: FastMA(0), n(0); { 2. 变量 }
FastMA = Average(Close, FastLen); { 3. 赋值 }
n = CurrentBar; { 3. 赋值 }
Plot1(FastMA, "Fast"); { 4. 画线(指标) }
If ... Then Buy ...; { 5. 下单(策略) }
2、语言基本规则
- 不区分大小写:
close和Close是同一个词。但建议固定大小写提高可读性 - 每条语句以分号
;结尾 - 注释:单行用
//,多行用{ }大括号 - 非执行词:
of、the、at等词只为提高可读性,执行时被跳过 - 回车、空格、缩进不影响执行,仅为可读性服务
3、常用标点速记
| 标点 | 作用 |
|---|---|
; | 语句结束 |
( ) | 函数参数 / 声明初始值 |
, | 分隔参数或多个声明 |
[ ] | 历史偏移(取过去K线)或数组下标 |
" " | 文本字符串(如订单名、Plot 名) |
{ } | 多行注释 |
// | 单行注释 |
三、Inputs 参数与 Variables 变量
1、Inputs:用户可调的参数
Inputs:
FastLength(10), { 默认 10 }
SlowLength(30), { 默认 30 }
StopLoss(500), { 默认 500(美元) }
TakeProfit(1000); { 默认 1000(美元) }
- 括号里是默认值,加到图表后可以在"格式化"对话框里改
- 改参数不用改代码,回测优化就是批量改 Inputs 试出最优组合
2、Variables:内部变量
Variables:
FastMA(0), { 数值型,初始 0 }
IsReady(False), { 布尔型 }
Tag("LE"); { 字符串型 }
- 类型由初始值决定:数字、布尔(True/False)、字符串
- 每根新K线,变量保持上一根的值继续算(除非声明为临时变量
Value1/Value2…,它们每根K线自动清零)
3、手数:代码说了算
下单时不写手数,就用策略属性(Strategy Properties)里 Trade size 的设置;代码里写了手数,就以代码为准:
Buy ("LE") 500 shares Next Bar at Market;
Sell Short ("SE") 10 contracts Next Bar at Market;
shares和contracts是同义词,股票用 shares 顺眼,期货用 contracts 顺眼- 手数可以是变量,实现动态仓位(见第十八章)
四、价格数据与历史引用
1、基础价格序列
| 保留字 | 含义 |
|---|---|
Open / High / Low / Close(或 O/H/L/C) | 当前K线开高低收 |
Volume(或 V) | 成交量 |
Date / Time | 当前K线日期/时间 |
2、历史偏移 [n]
Close[1] { 上一根K线收盘价 }
High[2] { 前两根K线最高价 }
Average(Close, 10)[1] { 均线在上一根K线的值 }
[0]是当前K线,[1]是上一根,以此类推
3、跨周期引用:HighD / LowD / CloseD / OpenD 家族
【注意】警告:常见误解纠正。 HighD(1) 不是"上一根K线的最高价"——它是前一个交易日(日线级别)的最高价。这个家族的正确含义:
| 函数 | 含义 |
|---|---|
HighD(1) | 前一交易日的最高价(分钟图、Tick图、日线图上都可用) |
LowD(1) | 前一交易日的最低价 |
CloseD(1) | 前一交易日的收盘价 |
OpenD(0) | 今天的开盘价(0 = 今日,1 = 前一交易日) |
官方使用要点:
- 参数
PeriodsAgo表示"往前数几个交易日",0 = 今天 - 图表里必须加载了足够的历史数据。比如要在 5 分钟图上取 25 天前的日内高点,图上至少要有 26 个完整交易日的 5 分钟数据;数据不够时函数返回 -1
- 函数以午夜零点作为"新的一天"分界。如果你交易夜盘品种、想按"收盘即隔天"来分日,官方建议改用 HighSession / LowSession 系列
- 家族还包括周线月线年版:
HighW/HighM/HighY(低开收同理)
官方示例——在前一日高点挂空头限价单:
SellShort Next Bar at HighD(1) Limit;
4、其他常用序列函数
Highest(High, 20) { 最近 20 根K线的最高价 }
Lowest(Low, 20) { 最近 20 根K线的最低价 }
五、常用内置函数
1、均线与波动率
| 函数 | 签名 | 说明 |
|---|---|---|
Average | Average(Price, Length) | 简单移动平均 SMA |
XAverage | XAverage(Price, Length) | 指数移动平均 EMA |
AvgTrueRange | AvgTrueRange(Length) | ATR 真实波幅均值 |
StandardDev | StandardDev(Price, Length, 1) | 标准差。第 3 参 =1 是总体标准差(除以 N),=2 是样本标准差(除以 N-1) |
白话注解:手写布林带时第三参要填 1。填 2 会算出样本标准差,带宽比标准布林带更宽,这是最经典的"ddof 坑"。
2、经典指标
| 函数 | 签名 | 说明 |
|---|---|---|
RSI | RSI(Close, 14) | 相对强弱指数 |
MACD | MACD(Price, FastLen, SlowLen) | MACD 值 = 快 EMA − 慢 EMA,三参数 |
BollingerBand | BollingerBand(Price, Length, NumDevs) | 布林带。NumDevs 正数取上轨,负数取下轨 |
ADX | ADX(Length) | 平均趋向指数 |
【注意】警告 1:MACD(Close, 12, 26, 9) 是错误写法。内置 MACD 函数只接受三个参数。想要"信号线(DEA)",要自己对 MACD 值再取均值:
Variables: MacdLine(0), SignalLine(0);
MacdLine = MACD(Close, 12, 26); { DIF:三参数 }
SignalLine = XAverage(MACD(Close, 12, 26), 9); { DEA:手动二次平均 }
【注意】警告 2:布林带函数名是 BollingerBand,不存在 Bollinger(Close, 20, 2) 这个函数。官方签名 BollingerBand(Price, Length, NumDevs),NumDevs 为标准差倍数:
Variables: UpBand(0), LoBand(0);
UpBand = BollingerBand(Close, 20, 2); { 上轨 }
LoBand = BollingerBand(Close, 20, -2); { 下轨 }
两个警告都对照 TradeStation 官方函数帮助页核实过。
3、数学与取整
MaxList(A, B, C) { 取最大 }
MinList(A, B, C) { 取最小 }
Floor(4.5) { 向下取整 = 4 }
Ceiling(4.5) { 向上取整 = 5 }
Round(142.3215, 2) { 四舍五入到 2 位 = 142.32 }
Abs(-3) { 绝对值 }
Power(2, 10) { 2 的 10 次方 }
六、四个下单指令与五种委托方式
1、四个下单指令
| 指令 | 作用 |
|---|---|
Buy | 建立多头(有空仓会先平空再开多) |
Sell Short | 建立空头 |
Sell | 平掉多头 |
BuyToCover | 平掉空头 |
【注意】警告:平空指令是 BuyToCover,一个词连写,不是 Buy To Cover。
官方语法骨架(方括号部分可选,只有指令词和委托方式是必填):
Buy [("订单名")] [手数 shares/contracts] [委托方式];
2、五种委托方式(官方枚举)
| 写法 | 含义 |
|---|---|
this bar on close | 当前K线收盘价成交 |
next bar at open(= next bar at market) | 下一根K线开盘市价 |
next bar at 价格 limit | 下一根K线限价单 |
next bar at 价格 stop | 下一根K线止损单 |
Buy ("LE") Next Bar at Market; { 下一根开盘市价开多 }
Buy ("LE") 10 Contracts Next Bar at 50 Stop; { 突破 50 止损单开多 }
Buy 2 Shares Next Bar at 100 Limit; { 100 以下限价开多 }
Sell ("LX") Next Bar at Market; { 平多 }
BuyToCover ("SX") Next Bar at Market; { 平空 }
If Time = 1500 Then Sell This Bar on Close; { 收盘平仓 }
3、This Bar 的三条官方铁律(错误码核实)
TradeStation 官方语法错误码表明确列出:
| 错误码 | 规则 |
|---|---|
| 30262 | 市价单只能用于 next bar。Buy This Bar at Market 直接报错 |
| 30263 | 止损单和限价单只能用于 next bar,不能放在 this bar |
| 30264 | this bar 只能搭配 on close,别无选择 |
白话注解:因为代码永远是在"当前K线收盘"这一刻跑的,当前K线已经走完了,你不可能在它的盘中"现在"成交。想今天收盘走人,只能写Sell This Bar on Close;想盘中止损,只能提前一根K线挂好next bar at 价格 Stop。
4、委托生命周期:一根 Bar
策略委托只活一根K线:下一根K线内没成交的限价/止损单会被取消,不会一直挂着。想持续挂单,必须每根K线重新满足条件重新发单。这个特性和 MT4 的挂单完全不同,迁移过来的人经常踩。
5、给订单起名
多个进场信号混在一个策略里时,给每个进场起名字,图表箭头和绩效报告里都能分清是谁下的:
Buy ("Breakout") Next Bar at Highest(High, 20)[1] + 1 Point Stop;
Buy ("Pullback") Next Bar at Average(Close, 20) Limit;
起名后还能把平仓单绑定到指定进场单(在 Sell 语句里用 From Entry 语法指定),实现分批分次出场。
七、持仓与绩效查询
1、MarketPosition:持仓方向
If MarketPosition = 1 Then ... { 持多 }
If MarketPosition = -1 Then ... { 持空 }
If MarketPosition = 0 Then ... { 空仓 }
MarketPosition(1) { 前一个仓位的方向(参数 = 往前数第几个仓位,最多 10) }
【注意】注意:MarketPosition 只告诉你方向,不告诉你手数。
2、CurrentContracts:持仓手数
If CurrentContracts = 10 Then ...
只有数量没有方向——和 MarketPosition 正好互补。两个一起用才知道"持多 10 手"。
3、进出场明细
| 函数 | 含义 |
|---|---|
EntryPrice(Num) | 第 Num 个仓位(0=当前,最多回看 10 个)的进场价 |
EntryDate(Num) / EntryTime(Num) | 进场日期/时间 |
BarsSinceEntry(Num) | 距离第 Num 个仓位进场过了几根K线。只在策略内有效 |
【注意】BarsSinceEntry 的官方特别提醒:它的返回值在 this bar 单和 next bar 单下行为不同——next bar 进场的,在"发单那根K线收盘"和"成交那根K线"都返回 0;this bar 进场的,发单那根返回的是旧仓位的值。做"进场满 N 根K线离场"时务必用实盘同款委托方式回测。
4、绩效与浮动盈亏
OpenPositionProfit { 当前浮动盈亏(美元) }
NetProfit { 已平仓净利累计(美元) }
TotalTrades { 已完成交易笔数 }
官方示例——浮盈达标就走:
If OpenPositionProfit >= 200 Then Begin
Sell Next Bar at Market;
BuyToCover Next Bar at Market;
End;
5、当日进场次数:EntriesToday / ExitsToday
If EntriesToday(CurrentDate) >= 3 Then ...
{ 今天已进场 3 次就不再进场。只在策略内可用,最多回看 10 个仓位 }
- 参数填日期(如
CurrentDate或Date),返回当天进场次数 - 对应还有
ExitsToday - 夜盘坑见第十七章
6、图表周期判断
BarType { 0=Tick 1=分钟 2=日线 3=周线 4=月线 }
BarInterval { 分钟线的分钟数,如 5 分钟图返回 5 }
If BarType = 1 and BarInterval = 5 Then ... { 只在 5 分钟图生效 }
7、品种属性:让止损代码跨品种通用
| 保留字 | 含义 |
|---|---|
MinMove / PriceScale | 最小跳动价格 = MinMove / PriceScale(即 Point) |
Point | 一个最小跳动单位的价格值 |
BigPointValue | 价格整数变动 1 对应的美元价值(如 E-mini S&P = 50) |
白话注解:写+ 1 Point平台自动换成该品种的最小跳动值;写美元金额时乘BigPointValue把"几点"换算成"几美元"。有了这两个词,同一套代码换品种不用改数字。
八、内置止损六件套与单位陷阱
1、六个内置止损指令(官方全表)
| 指令 | 作用 |
|---|---|
SetStopLoss(Amount) | 亏损达 Amount 触发市价离场 |
SetProfitTarget(Amount) | 盈利达 Amount 触发市价离场 |
SetBreakEven(Floor) | 浮盈超过 Floor 后,止损上移到进场价 |
SetDollarTrailing(Amount) | 从最大浮盈回撤 Amount 触发离场(美元追踪止损) |
SetPercentTrailing(Floor, Pct) | 浮盈超过 Floor 后,从峰值利润回撤 Pct(小数,如 0.5 = 50%)触发离场 |
SetExitOnClose | 收盘强制平仓 |
2、最大的单位陷阱:Amount 是美元,不是点!
官方文档原文:SetStopLoss 的 Amount 参数是 "Amount of loss, in dollars"(亏损金额,单位美元)。旧教程里"SetStopLoss(50) = 止损 50 点"是错误理解:
| 口径切换词 | Amount 的含义 |
|---|---|
SetStopPosition(默认,可不写) | Amount = 整个仓位的美元盈亏 |
SetStopContract / SetStopShare(同义) | Amount = 每手/每股的美元盈亏 |
官方两个对照示例:
{ 整仓口径:500 股 MSFT,SetStopLoss(200) = 全仓亏 200 美元离场,即每股 0.4 美元 }
SetStopPosition; { 默认,可省略 }
SetStopLoss(200);
{ 每股口径:SetStopLoss(0.6) = 每股亏 0.6 美元离场,500 股全仓亏 300 美元 }
SetStopShare;
SetStopLoss(0.6);
3、跨品种通用的正确姿势:SetStopContract + BigPointValue
官方教程给出的模板——把"点数"换算成美元再交给内置止损:
Inputs: StopPts(5);
Vars: StopAmt(0);
StopAmt = StopPts * BigPointValue; { 点数 → 美元 }
SetStopContract;
SetStopLoss(StopAmt); { 每手亏 StopPts 个大点离场 }
4、内置止损的三个特性(官方原文核实)
- 进场当根 Bar 就生效:内置止损由策略引擎内部逐 tick 监控,不受逐 Bar 计算限制——长周期图(30 分钟/小时/日线)上尤其有用,不用等下一根K线才知道止损打掉了
- 触发即市价单:打掉就发市价单离场,信号名固定为
Stop Loss等 - 断网即失效:官方明确注明,这种止损单由你本机电脑监控,一旦断开网络连接,止损就不再工作。实盘必须理解这一点(详见第二十一章)
白话注解:内置止损是"引擎帮你盯",不是"交易所服务器帮你盯"。它不是送进券商的真止损单。电脑关了、网断了、软件崩了,止损就没了。想挂真止损到交易所,得手写 next bar at 价格 Stop 的离场单(配合支持持续挂单的券商设置)。
九、交叉判断 Crosses Over / Under
1、官方写法
If FastMA Crosses Over SlowMA Then ... { 上穿 }
If FastMA Crosses Under SlowMA Then ... { 下穿 }
Crosses Over / Crosses Under 两个词必须成对出现,官方错误码 30291 明确:只写 Crosses 不带 Over/Under 直接报语法错。
2、两个官方错误码
| 错误码 | 规则 |
|---|---|
| 30291 | Cross 后面缺 Over/Under → 报错 |
| 30292 | 两个常量之间不能 Cross(10 Crosses Over 15 报错——常数永远不会穿越) |
3、等价函数写法
内置也有函数形式的交叉判断:
CrossesAbove(FastMA, SlowMA) { 返回 True 当根K线发生上穿 }
CrossesBelow(FastMA, SlowMA)
自己手写等价逻辑则是一根K线的状态组合:
GoldenCross = FastMA > SlowMA and FastMA[1] <= SlowMA[1];
手写版的好处是能精确控制"上一根相等算不算穿越"这类边界条件。
十、Next Bar 执行模型与未来函数
1、执行模型
- 策略代码在每根K线收盘时执行一遍
- 此时发出的委托在下一根K线上成交(市价=开盘价)
- 所以策略天然没有"用当前K线收盘价信号、又按同一价格成交"的作弊空间
2、未来函数从哪来
虽然框架帮你防了大部分,这些写法照样能造出未来函数:
- 引用未收盘数据做决策还按当根价格成交:IOG 模式下用
Close[0](还在跳动的当前价)判断并立即发单,历史回测会用收盘值模拟、实盘却是半截价——回测虚高 - Highest/Lowest 包含当前未走完的 Bar:突破策略里
Highest(High, 20)包含了当前Bar,买点实际永远高于"真实突破价"。规范写法用Highest(High, 20)[1]——上一根为止的 20 根最高 - 指标回看长度不足:MaxBarsBack 太小会让指标从头算错若干根
3、MaxBarsBack
任何用到 Close[100] 或 100 周期均线的策略,都要求平台往前加载足够的历史Bar。两个办法:
- 策略属性里手动设置 MaxBarsBack ≥ 你用到的最大回看长度
- 或选 Auto Detect 让平台自己猜(偶尔猜小了,前几十根K线信号不可信,回测开头那段别当真)
十一、限价/止损单的"一根 Bar 寿命"与追单
1、问题:委托当根未成交就取消
{ 想在突破位挂买单,但下一根没碰到就没了 }
If MarketPosition = 0 Then
Buy Next Bar at Highest(High, 20)[1] + 1 Point Stop;
策略委托的生命只有一根K线。好处是不会留一堆陈年旧单;坏处是条件消失后单就没了。
2、解决:状态变量保持条件
Inputs: SetupLen(3);
Variables: PendBuy(False), Trigger(0);
{ 盘整 3 根后记录触发价,进入挂单状态 }
If MarketPosition = 0 and Highest(High, SetupLen)[1] = Lowest(High, SetupLen)[1] + 3 * Point Then Begin
PendBuy = True;
Trigger = Highest(High, SetupLen)[1] + 1 Point;
End;
{ 挂单状态持续期间,每根K线都重发委托 }
If PendBuy and MarketPosition = 0 Then
Buy Next Bar at Trigger Stop;
{ 已进场就清状态 }
If MarketPosition = 1 Then PendBuy = False;
3、限价单与止损单的方向约定
| 买方向 | 逻辑 |
|---|---|
Buy at X Limit | X 或更低成交(低价接) |
Buy at X Stop | X 或更高成交(突破追) |
Sell at X Limit | X 或更高成交(高价出) |
Sell at X Stop | X 或更低成交(跌破走) |
方向写反了,委托每根都会被立即取消或立即成交,回测里表现为"莫名秒进秒出"。
十二、IOG 逐笔计算
1、什么是 IOG
Intrabar Order Generation(逐 Bar 内下单):默认模式下策略每根K线收盘才算一次;打开 IOG 后,实时行情每个 tick 都会触发计算(历史回测按开高低收四个点模拟),可以在K线内部反复进出。
2、打开方式
- MultiCharts:Format Signal → Properties 勾选 Intrabar Order Generation;.NET 信号也可用类特性
[IOGMode(IOGMode.Enabled)] - TradeStation:Format Strategy → Calculation 勾选 Intrabar Order Generation
3、IOG 的代价(官方明确)
- 历史回测精度依赖数据:逐Bar模拟只有开高低收四个点,实盘 tick 走势复杂得多——IOG 策略回测与实盘差异天然大
- 每 Bar 进出次数要设限:MC 官方提供三档——每根 Bar 限一次进场+一次出场 / 只许一次进场一次出场 / 不限次数。不限次数+震荡行情=疯狂来回打脸
- 与"下一根开盘"模式互斥:MC 官方注明,
[IOGMode(IOGMode.Enabled)]和[CalcAtOpenNextBar(true)]两个特性同时用会直接报错
4、MC 特有:开盘计算模式
MC .NET 支持 [CalcAtOpenNextBarAttribute(true)]:改为在下一根K线开盘时用当前收盘数据计算。此时下一根开盘价已经真实可知:
double o_next_bar = Bars.Open[-1]; { 下一根的开盘价 }
double h = Bars.High[0]; { 已收盘那根的最高价 }
if (o_next_bar > h) sellshort_order.Send(); { 跳空高开做空 }
官方示例用它写"跳空策略":开盘跳空向上就做空、跳空向下就做多。传统"next bar at market"模式下开盘价是估不出来的,这个模式才写得出来。
白话注解:新手建议老实待在默认逐 Bar 收盘模式。IOG 是给剥头皮和高频准备的,回测可信度先掉一半,还得自己处理防重复下单。
十三、多数据流 Data2
1、引用第二个品种
图表上可以插入多个数据流(不同品种或不同周期),代码里用 Data 编号引用:
If Close of Data2 > Average(Close of Data2, 50) Then ...
If Average(Close, 4) of Data2 > 0 Then ...
2、官方限制:next bar 价格禁止混用副数据流
官方错误码 30265:同一个策略里,既引用 Open Next Bar / Time Next Bar 这类"下一根价格",又引用 Data2 副数据流,直接报错。官方建议:拆成两个策略分别挂图。
{ 同一个策略里这两句并存会触发 30265: }
If Open Next Bar > High Then SellShort Next Bar at Open Next Bar + Range Limit; { 用了 next bar 价格 }
If Average(Close, 4) of Data2 > 0 Then ... { 用了 Data2 }
3、使用注意
- Data2 的K线周期和 Data1 不同步时,
Close of Data2取的是"Data2 上最近一根已收盘K线"的值 - Data2 数据加载不足会让策略前期信号全错,检查图表加载量
十四、Print 调试与格式化输出
1、Print 语句
Print(Date, " ", Time, " Close=", Close, " MP=", MarketPosition);
- 输出到编辑器的打印日志(PowerEditor 的 Output / Print Log 窗口)
- 回测时逐根输出,排查"为什么这根没进场"全靠它
2、格式化数字
默认打印可能糊成一团,用 :宽度:小数位 格式:
Print(Close:5:2, " ", MyValue:8:5); { 5 位宽 2 位小数;外汇期货常用 5 位小数 }
3、文件输出
FileAppend("C:\temp\log.txt", NumToStr(Close, 2) + NewLine);
【注意】官方限制:文件路径不能超 260 字符、不能含非法字符,路径写错直接报语法错。Print 够用就别用文件。
十五、防重复下单与每日次数限制
1、防重复:持仓守卫
信号条件可能连续几根K线都成立,不加守卫会反复进场:
{ 只在空仓时进场 }
If MarketPosition = 0 and FastMA Crosses Over SlowMA Then
Buy Next Bar at Market;
{ 反手场景:持多才允许翻空,反之亦然 }
If MarketPosition = 1 and FastMA Crosses Under SlowMA Then
Sell Short Next Bar at Market;
2、EntriesToday 限次与"夜盘重置"坑
If MarketPosition = 0 and Condition1 and EntriesToday(CurrentDate) < 3 Then
Buy Next Bar at Market;
官方口径:EntriesToday 只能在策略里用,最多回看 10 个仓位。 它按自然日(午夜)重置——夜盘品种半夜翻日,次数限制会在盘中突然清零,约束失效。想按"交易日"控制次数,用手动计数器:
Variables: TradesCounter(0), MP(0);
MP = MarketPosition;
{ 发现仓位方向从 0 变成非 0 → 新进场,计数 +1 }
If MP <> 0 and MP[1] = 0 Then
TradesCounter = TradesCounter + 1;
{ 跨日清零(分钟图) }
If Date <> Date[1] Then
TradesCounter = 0;
If TradesCounter < 15 and Condition1 and MarketPosition = 0 Then
Buy Next Bar at Market;
手动计数器还能按你自定义的时间点重置(比如美股日盘开盘清零),灵活性远超 EntriesToday。
十六、TradeStation 与 MultiCharts 差异对照
1、平台定位
| 维度 | TradeStation | MultiCharts |
|---|---|---|
| 语言 | EasyLanguage | PowerLanguage(兼容 EL) |
| 编辑器 | EasyLanguage PowerEditor | PowerLanguage Editor(独立窗口) |
| 编译/校验 | Verify(校验)按钮 | F7 编译 |
| 经纪商绑定 | 与 TradeStation 券商深度绑定 | 独立软件,支持多家经纪商与数据源接入 |
| .NET 扩展 | 无(用自家 C# / TSData 组件体系) | PowerLanguage .NET(C#) |
2、代码兼容性
- 绝大多数核心语法一致:
Inputs/Variables/Buy/Sell Short/SetStopLoss/MarketPosition等两边通用 - 个别函数实现细节与默认参数不同,复制代码后先编译看报错,再逐个修
- 回测设置项名称不同(TS 在 Format Strategy 的 Calculation 页,MC 在 Properties 页),功能基本对应
白话注解:国内用户用 MultiCharts 更多(能接国内期货公司通道);TradeStation 适合美股期货用户。学语言时不用纠结平台,语法 95% 以上通用。
十七、PowerLanguage .NET(C# 扩展)
1、适用场景
纯 PowerLanguage 写不动的逻辑(复杂循环、外部数据接口、自定义集合运算),MultiCharts 提供 .NET 版本,用 C# 写策略。官方手册结构:Signal 类继承 SignalObject,核心是三个生命周期方法。
2、官方核实过的最小骨架
【注意】警告:老教程里 Exec.Buy("LE", 1, ...)、Bars.Close[0].EMA(10)、CrossAbove(fast, slow) 这类写法在 PowerLanguage .NET 里不存在(对照 MultiCharts 官方《How to Create a .NET Strategy》教程核实)。官方下单模式是 OrderCreator 创建订单对象 + Send() 发送:
public class MyFirstSignal : SignalObject
{
public MyFirstSignal(object _ctx) : base(_ctx) { }
[Input] public int FastLength { get; set; } // 输入参数 = 带特性 [Input] 的属性
[Input] public int SlowLength { get; set; }
private IOrderMarket m_LE; // 订单对象
private IOrderMarket m_SE;
private IOrderMarket m_LX;
private IOrderMarket m_SX;
private ISeries<double> m_fast;
private ISeries<double> m_slow;
protected override void Create() // 启动时执行一次:建对象
{
m_LE = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, "LE", EOrderAction.Buy));
m_SE = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, "SE", EOrderAction.SellShort));
m_LX = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, "LX", EOrderAction.Sell));
m_SX = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, "SX", EOrderAction.BuyToCover));
}
protected override void StartCalc() // 每次计算开始:初始化变量
{
m_fast = new AverageSeries(Bars.Close, FastLength);
m_slow = new AverageSeries(Bars.Close, SlowLength);
}
protected override void CalcBar() // 每根K线执行
{
if (m_fast[1] <= m_slow[1] && m_fast[0] > m_slow[0])
m_LE.Send(); // 金叉:发送下一根市价买单
if (m_fast[1] >= m_slow[1] && m_fast[0] < m_slow[0])
m_SE.Send();
}
}
3、关键概念对照表(官方手册核实)
| PowerLanguage | PowerLanguage .NET |
|---|---|
Inputs: Len(10); | [Input] public int Length { get; set; },默认值写在构造函数 |
Variables: x(0); | C# 字段 / VariableSeries<double>(跨Bar保持的序列) |
Buy Next Bar at Market; | OrderCreator.MarketNextBar(new SOrderParameters(...)) 创建,Send() 发送 |
Close[1] | Bars.Close[1] |
Average(Close, 10) | new AverageSeries(Bars.Close, 10) 等系列类 |
| 逐 Bar 收盘计算 | CalcBar();开盘计算加 [CalcAtOpenNextBarAttribute(true)] |
| IOG 勾选 | [IOGMode(IOGMode.Enabled)](与 CalcAtOpenNextBar 互斥) |
| — | Bars.OpenNextBar() / Bars.Open[-1] 取下一根开盘价(开盘计算模式专用) |
4、EOrderAction 四枚举(官方教程核实)
| 枚举 | 对应 PowerLanguage |
|---|---|
EOrderAction.Buy | Buy |
EOrderAction.SellShort | Sell Short |
EOrderAction.Sell | Sell(平多) |
EOrderAction.BuyToCover | BuyToCover(平空) |
5、使用建议
能用纯 PowerLanguage 就用纯的:调试快、资料多、社区代码能直接抄。.NET 版只在需要复杂计算、访问外部 .NET 库、或做界面化工具时才上。
十八、实盘部署与自动化
1、启动自动化
MultiCharts:
- 信号加入图表 → Format Signal → Properties
- 勾选 Enable Automation(自动化),选好账户与方向许可(只允许多/只允许空/双向)
- 确认 Strategy Properties 里的默认手数、进出规则
- 观察信号箭头与 Tracker(策略追踪器)确认下单正常
TradeStation:Format Strategy → Automation 页,勾选实盘账户自动化,逐项确认确认弹窗。
2、断线风险:内置止损不是交易所止损
第九章说过,这里在实盘语境下再说一遍。官方原文:内置止损(SetStopLoss 等)产生的离场单由你的电脑监控,达到条件才发市价单——
- 断网 → 止损失效
- 断电、软件崩溃 → 止损失效
- 策略引擎重算/重载图表时可能出现状态不一致
实盘必做:
- 能挂到交易所的真止损就挂真止损(券商端支持的服务器侧 GTC 止损单)
- 桌面客户端 7×24 跑策略必须配 VPS:远程 Windows 服务器,装平台、登账户、挂图,电脑关机策略照跑
- VPS 上关掉 Windows 自动更新重启,或设置开完机自动登录并自启平台
- 每天开盘前人工检查:图表还活着吗?信号状态正常吗?持仓对得上吗?
3、回测 实盘的过桥清单
- 回测加了手续费与滑点吗?
- 用模拟盘(Simulation / Paper Trading 账户)跑过至少一个月吗?
- 先小手数实盘验证成交质量(滑点、拒单、部分成交)了吗?
- 最大回撤你能承受三倍吗?(实盘回撤几乎必然大于回测)
- 参数是否过拟合?(同一参数在多个时间段、多个品种上都试过吗)
回测 ≠ 实盘,业绩不代表未来收益。自动化只是执行工具,执行得再快,策略本身没优势就是亏得更快。
十九、从 MQL4 迁移对照表
1、概念映射
| MQL4 | EasyLanguage / PowerLanguage | 迁移要点 |
|---|---|---|
OnInit() / start() / OnTick() | 无显式函数,整个代码每根Bar跑一遍 | 心法转变:EL 是"每根收盘过一遍全代码" |
iMA(...) | Average(Close, Len) | EL 直接写价格序列,不用传 symbol/timeframe |
OrderSend(OP_BUY...) | Buy Next Bar at Market; | EL 委托只能下一根Bar生效(或 this bar on close) |
OrdersTotal() / 持仓查询 | MarketPosition / CurrentContracts | 方向和手数分两个保留字 |
OrderClose() | Sell / BuyToCover Next Bar at Market; | 平多/平空是两个不同指令 |
Point / MarketInfo(MODE_TICKVALUE) | Point / BigPointValue | BigPointValue = 价格整数 1 的美元价值 |
Ask / Bid | 无直接对应(策略按 Bar 成交模型) | EL 是 Bar 级撮合,不直接盯买卖价 |
| 止损随单送交易所 | SetStopLoss 本机监控 / 手写 next bar stop 单 | EL 内置止损断线失效,见第二十一章 |
| 回测:策略测试器 | 图表内直接回测 + Strategy Performance Report | 回测与图表信号同一套引擎 |
2、思维转换三条
- 从"事件回调"到"逐Bar全量重算":MQL4 想的是"tick 来了执行函数";EL 想的是"每根K线收盘,把整套逻辑从头过一遍"
- 从"随时下单"到"下一根Bar成交":EL 的市价单没有"当场成交"概念(IOG 模式除外),信号→成交天然隔一根Bar
- 从"仓位自由管理"到"策略仓位模型":EL 平台自带仓位记账(进场名、绩效报告),多数时候不用自己遍历订单
💬 用户评价 (0)
立即登录