tbl语言示例
例如,在TradeBlazer公式中经常使用的一个用户函数Summation,Summation通过输入Price序列数据,以及 Length统计周期数,计算Price最近Length周期的和,每次用户需要进行求和计算的时候,都可以调用Summation代替冗长的求和代码, 输入参数并获取返回值。 Summation是TradeBlazer公式中一个比较简单的用户函数,TradeBlazer公式提供了上百个内建用户函数,当然,您也可以编写您自己的用户函数。 用户函数通过参数传递输入数据,通过引用参数或返回值传递输出数据,以上例子中的Summation函数,在被调用的时候格式如下: Value1 = Summation(Close,10);在调用Summation的时候,需要根据定义时候的参数列表和顺序,输入相应的输入参数,有默认值的参数可以省略输入参数。 用户函数在交易开拓者中使用有如下规则:
- 支持九种类型的参数定义,支持指定参数默认值;
- 支持使用引用参数,可通过引用参数返回多个数据;
- 支持六种类型的变量定义,支持指定变量的默认值;
- 可以访问Data0-Data49个数据源的Bar数据;
- 可以访问行情数据、属性数据;
- 必须通过Return返回数据,返回数据类型为三种基本类型之一;
- 脚本中的返回数据类型必须和属性界面设置中一致;
- 用户函数之间可以相互调用,用户函数自身也可以递归调用;
- 用户函数可以根据设置调用部分的系统函数。
用户函数的类型用户函数按照返回值类型不同可以分为数值型(Numeric),布尔型(Bool),字符串(String)三种基本类型,三种类型用户函数在调用时需要将返回值赋予类型相同的变量。 按照用户函数属性不同,用户函数可以分为内建用户函数和其他用户函数两种,内建用户函数是交易开拓者提供的,用于支持公式系统运行的预置公式,您可以查看和调用内建用户函数,但是不能删除和修改内建公式。 按照用户函数的实现机制不同,用户函数可分为普通函数和序列函数。普通函数和其他语言的函数类似,输入参数,执行一段程序代码,返回需要的值。序列函数是输入参数或变量中有序列数据类型的用户函数。 序列函数序列函数是一种特殊的用户函数,当它的参数或变量中使用了序列数据,我们就称之为序列函数,序列数据作为普通计算机语言和TB语言的重要区别,是进 行金融序列数据计算的核心。为了保证序列数据的正确计算,序列函数需要每个Bar都被调用,如果有些Bar没有调用序列函数,序列函数中的序列数据则是上 一个Bar的值。除非是您的算法需要,否则建议不要在条件语句,条件语句的判断表达式,循环语句中使用序列函数。 使用内建用户函数TradeBlazer公式中提供上百个内建用户函数,一部分用户函数提供类似于求和,求平均,求线性回归等算法方面的功能,另外一些函数提供技术分析的一些算法,比如:RSI,CCI,DMI等,这些用户函数用户辅助完成技术分析。 在创建自己的技术分析和交易系统时,如果需要自己写一些算法,您可以首先在用户函数中查找是否有相应的内建用户函数,尽可能的多使用内建用户函数,减少出错的可能。您也可以编写自己的算法,以供在技术分析和交易系统中使用。 用户函数的参数大部分用户函数都需要接受输入的信息进行计算,这些输入的信息,我们称之为参数。关于用户函数参数的使用详细说明参见参数。 如何编写用户函数一个用户函数由三部分组成,参数定义,变量定义,脚本正文。 语法如下: Params 参数定义语句;Vars 变量定义语句;Begin 脚本正文;End参数定义和变量定义部分在前面已经详细叙述过,脚本的正文部分将输入参数进行计算,得出函数的返回值,并通过Return返回。 例如,我们以Average为例,Average计算Price在Length周期内的平均值。Average调用Summation求和,并计算平均值,然后返回结果,脚本如下: Params NumericSeries Price(1); Numeric Length(10);Vars Numeric AvgValue; Begin AvgValue = Summation(Price, Length) / Length; Return AvgValue;End对于使用多个输出的情况,即使用引用参数的情况,我们以求N周期最大值为例进行描述,假定我们需要编写一个用户函数,该函数需要求出序列变量Price在最近Length周期内的最大值,并且要求出最大值出现的Bar和当前Bar的偏移值。脚本如下: Params NumericSeries Price(1); Numeric Length(10); NumericRef HighestBar(0);Vars Numeric MyVal; Numeric MyBar; Numeric i; Begin MyVal = Price; MyBar = 0; For i = 1 to Length - 1 { If ( Price > MyVal) { MyVal = Price; MyBar = i; } } HighestBar = MyBar; Return MyVal;End用户函数的调用用户函数成功创建之后(编译/保存成功),您可以在其他的用户函数、技术分析、交易指令等公式中调用用户函数,调用用户函数时需要注意保持参数类型 的匹配,即用户函数参数的声明数据类型需和调用时传入参数的数据匹配,这是所指的匹配是指基本数据类型:数值型,布尔型,字符串三种类型匹配,并且保持序 列参数和传入变量类型的对应。我们可以对用户函数定义为Numeric或者NumericRef的参数使用Numeric类型的变量作为传入参数;但不能 将在定义为NumericSeries类型的参数时传入Numeric。具体的对应关系如下表:
函数参数声明类型
|
可传入的变量类型
|
Numeric
|
Numeric,NumericRef,NumericSeries
|
NumericRef
|
Numeric,NumericRef,NumericSeries
|
NumericSeries
|
NumericSeries
|
Bool
|
Bool,BoolRef,BoolSeries
|
BoolRef
|
Bool,BoolRef,BoolSeries
|
BoolSeries
|
BoolSeries
|
String
|
String,StringRef,StringSeries
|
StringRef
|
String,StringRef,StringSeries
|
StringSeries
|
StringSeries
|
对于函数的返回值,您也可以将用户函数的Numeric返回值赋值给NumericSeries或NumericRef变量。即在用户函数的返回值使用时,忽略其扩展数据类型。比如我们在调用Average求平均值时,可以这样调用: Vars Numeric Value1;Begin Value1 = Average(Close,10); ...End我们也可以按照以下方式进行调用: Vars NumericSeries Value1;Begin Value1 = Average(CloseTmp,10); ...EndA用户函数调用自身,我们称之为直接递归;A用户函数可以调用B用户函数,同时B用户函数也可以调用A用户函数,对于这种的情况,我们称之为间接递归; 不管是直接递归还是间接递归,用户函数在执行的时候,都可能遇到递归调用没有出口,导致死循环的情况。因此,我们在编写公式的时候,要注意避免使用递归算法,如果一定需要使用递归算法,要注意保证递归算法都有出口。 用默认参数调用用户函数用户函数在被调用的时候,如果传入的参数和参数的默认值一样,可以省略输出参数,使用默认值来调用用户参数。只能够对排列在后面的那些参数使用默认参数,默认参数的定义参见参数。 公式应用
技术指标
当技术指标应用在图表中时,您可以设置技术指标各输出值的表现形式,以及颜色、粗细等,如下图的点,线,柱状图所示:
示例,技术指标RSI,脚本如下: Params Numeric Length(14); Numeric OverSold(20); Numeric OverBought (80);Vars Numeric RSIValue(0); Numeric RSIColor(-1);Begin RSIValue = RSI(Close,Length); If (RSIValue > OverBought) { RSIColor = RED; }Else If (RSIValue < OverSold) { RSIColor = CYAN; } PlotNumeric("RSI1", RSIValue, RSIColor); PlotNumeric("超卖", OverSold); PlotNumeric("超买", OverBought); If CrossOver(RSIValue,OverSold) { Alert("Indicator exiting oversold zone"); } If CrossUnder(RSIValue, OverBought) { Alert("Indicator exiting overbought zone"); }End公式应用RSI调用RSI内建用户函数计算出结果,然后判断其返回值和超买,超卖的关系,设置显示颜色,并产生报警信息。 公式应用在输出数据时,我们是通过输出值的名称来进行识别,名称相同则认为是一个数据,如下的代码,后面语句的输出数据将会覆盖前面语句的输出数据。 PlotNumeric("Test",10)lotNumeric("Test",20);最后"Test"输出的数据为20,而不是10。 常用的技术指标类函数有PlotNumeric、PlotString、PlotBool、UnPlot、Alert。 交易策略
TradeBlazer公式提供四个交易函数和现实中的四种交易动作进行对应,列表如下:
函数名
|
描述
|
Buy
|
平掉所有空头持仓,开多头仓位。
|
Sell
|
平掉指定的多头持仓。
|
SellShort
|
平掉所有多头持仓,开空头仓位。
|
BuyToCover
|
平掉指定的空头持仓。
|
示例,以下是一个双均线交易策略的代码: Params Numeric FastLength(5); Numeric SlowLength(20); Numeric BuyLots(1);Vars NumericSeries AvgValue1; NumericSeries AvgValue2; Begin AvgValue1 = AverageFC(Close,FastLength); AvgValue2 = AverageFC(Close,SlowLength); If(MarketPosition!=1 And (AvgValue1[1] > AvgValue2[2])) { Buy(BuyLots,Open); } If(MarketPosition!=-1 And (AvgValue1[1] < AvgValue2[2])) { SellShort(BuyLots,Open); }End为了在上面交易策略在超级图表中执行同时看到两条均线的数值,我们也可以在交易策略中输出指标线条,只需要增加以下两行代码: PlotNumeric("MA1",AvgValue1); PlotNumeric("MA2",AvgValue2);除了希望看到两条均线值之外,我们还希望能够在超级图表中看到交易策略的盈亏曲线,这时我们需要再增加一条指标线: PlotNumeric("OpenEquity",Portfolio_TotalProfit);关于交易策略的更多使用参见交易策略进阶
系统函数
目前的系统函数支持四种数据类型,除了TradeBlazer公式中定义的三种基本数据类型:Bool,Numeric,String之外,新加入 Long(长整型)类型,使系统函数能够更加快捷的进行计算,TradeBlazer公式在处理的时候自动将Numeric和Long进行转化,用户无需 进行特别的处理。 TradeBlazer公式现有的系统函数主要分为:数据函数、时间函数、数学函数、其它函数、交易函数、属性函数、账户函数、颜色函数、字符串函数等。每个系统函数都有自己的适用范围和使用规范,详细说明参见附录。
交易策略进阶
止赢止损模板以止赢30跳,止损20跳为例,也可以转换为开仓价格的百分比值,或其任何设置的变量进行处理。 Vars Numeric MinPoint; // 一个最小变动单位,也就是一跳 Numeric MyEntryPrice; // 开仓价格,本例是开仓均价,也可根据需要设置为某次入场的价格 Numeric TakeProfitSet(30); // 止赢设置 Numeric StopLossSet(20); // 止损设置 Numeric MyExitPrice; // 平仓价格Begin ... MinPoint = MinMove*PriceScale; MyEntryPrice = AvgEntryPrice; If(MarketPosition==1) // 有多仓的情况 { If(High >= MyEntryPrice + TakeProfitSet*MinPoint) // 止赢条件表达式 { MyExitPrice = MyEntryPrice + TakeProfitSet*MinPoint; If(Open > MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 Sell(0,MyExitPrice); }else if(Low <= MyEntryPrice - StopLossSet*MinPoint)// 止损条件表达式 { MyExitPrice = MyEntryPrice - StopLossSet*MinPoint; If(Open < MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 Sell(0,MyExitPrice); } }else if(MarketPosition==-1) // 有空仓的情况 { If(Low <= MyEntryPrice - TakeProfitSet*MinPoint) // 止赢条件表达式 { MyExitPrice = MyEntryPrice - TakeProfitSet*MinPoint; If(Open < MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 BuyToCover(0,MyExitPrice); }else if(High >= MyEntryPrice + StopLossSet*MinPoint)// 止损条件表达式 { MyExitPrice = MyEntryPrice + StopLossSet*MinPoint; If(Open > MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 BuyToCover(0,MyExitPrice); } } ...End注意事项:
- 因无法确认开仓Bar最高/低价和开仓价的先后顺序,因此以上写法一般忽略开仓Bar的处理。
- 如果某个Bar最高/低价相差很大,可能出现止赢止损同时满足的情况,这种情况下需要切换到更小的周期进行交易,或者扩大止赢/损幅度。
跟踪止损跟踪止损有很多种方式,本模板的规则如下:当盈利达到50跳之后启动第一级跟踪止损,止损的回撤值为30跳,当盈利达到80跳之后启动第二级的跟踪止损,止损的回撤值为20跳。您也可以将这些固定的设置修改为盈利百分比,或者是某个价格的百分比。 Vars Numeric MinPoint; // 一个最小变动单位,也就是一跳 Numeric MyEntryPrice; // 开仓价格,本例是开仓均价,也可根据需要设置为某次入场的价格 Numeric TrailingStart1(50); // 跟踪止损启动设置1 Numeric TrailingStart2(80); // 跟踪止损启动设置2 Numeric TrailingStop1(30); // 跟踪止损设置1 Numeric TrailingStop2(20); // 跟踪止损设置2 Numeric StopLossSet(50); // 止损设置 Numeric MyExitPrice; // 平仓价格 NumericSeries HighestAfterEntry; // 开仓后出现的最高价 NumericSeries LowestAfterEntry; // 开仓后出现的最低价Begin ... If(BarsSinceentry == 0) { HighestAfterEntry = Close; LowestAfterEntry = Close; If(MarketPosition <> 0) { HighestAfterEntry = Max(HighestAfterEntry,AvgEntryPrice); // 开仓的Bar,将开仓价和当时的收盘价的较大值保留到HighestAfterEntry LowestAfterEntry = Min(LowestAfterEntry,AvgEntryPrice); // 开仓的Bar,将开仓价和当时的收盘价的较小值保留到LowestAfterEntry } }else { HighestAfterEntry = Max(HighestAfterEntry,High); // 记录下当前Bar的最高点,用于下一个Bar的跟踪止损判断 LowestAfterEntry = Min(LowestAfterEntry,Low); // 记录下当前Bar的最低点,用于下一个Bar的跟踪止损判断 } Commentary("HighestAfterEntry="+Text(HighestAfterEntry)); Commentary("LowestAfterEntry="+Text(LowestAfterEntry)); MinPoint = MinMove*PriceScale; MyEntryPrice = AvgEntryPrice; If(MarketPosition==1) // 有多仓的情况 { If(HighestAfterEntry[1] >= MyEntryPrice + TrailingStart2*MinPoint) // 第二级跟踪止损的条件表达式 { If(Low <= HighestAfterEntry[1] - TrailingStop2*MinPoint) { MyExitPrice = HighestAfterEntry[1] - TrailingStop2*MinPoint; If(Open < MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 Sell(0,MyExitPrice); } }else if(HighestAfterEntry[1] >= MyEntryPrice + TrailingStart1*MinPoint)// 第一级跟踪止损的条件表达式 { If(Low <= HighestAfterEntry[1] - TrailingStop1*MinPoint) { MyExitPrice = HighestAfterEntry[1] - TrailingStop1*MinPoint; If(Open < MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 Sell(0,MyExitPrice); } }else if(Low <= MyEntryPrice - StopLossSet*MinPoint)//可以在这里写上初始的止损处理 { MyExitPrice = MyEntryPrice - StopLossSet*MinPoint; If(Open < MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 Sell(0,MyExitPrice); } }else if(MarketPosition==-1) // 有空仓的情况 { If(LowestAfterEntry[1] <= MyEntryPrice - TrailingStart2*MinPoint) // 第二级跟踪止损的条件表达式 { If(High >= LowestAfterEntry[1] + TrailingStop2*MinPoint) { MyExitPrice = LowestAfterEntry[1] + TrailingStop2*MinPoint; If(Open > MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 BuyToCover(0,MyExitPrice); } }else if(LowestAfterEntry[1] <= MyEntryPrice - TrailingStart1*MinPoint)// 第一级跟踪止损的条件表达式 { If(High >= LowestAfterEntry[1] + TrailingStop1*MinPoint) { MyExitPrice = LowestAfterEntry[1] + TrailingStop1*MinPoint; If(Open > MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 BuyToCover(0,MyExitPrice); } }else If(High >= MyEntryPrice + StopLossSet*MinPoint)//可以在这里写上初始的止损处理 { MyExitPrice = MyEntryPrice + StopLossSet*MinPoint; If(Open > MyExitPrice) MyExitPrice = Open; // 如果该Bar开盘价有跳空触发,则用开盘价代替 BuyToCover(0,MyExitPrice); } } ...End注意事项:
- 因无法确认开仓Bar最高/低价和开仓价的先后顺序,因此以上写法一般忽略开仓Bar的处理。
- 如果某个Bar最高/低价相差很大,可能出现创新高之后跟踪止损的情况,但系统无法确认最高价和最低价的先后顺序,因此本模板只用前一个Bar的最高/低价计算最大赢利位置。
加仓减仓本例仅以做多为例,做空类似。模板以首次开仓2手后每赢利30跳加仓一次,每次1手,最多加仓3次;开仓后每亏损30跳减仓1手。也可以转换为开仓价格的百分比值,或波动率的百分比等其任何设置的变量进行处理。 Vars Numeric MinPoint; // 一个最小变动单位,也就是一跳 NumericSeries firstPrice; // 第一次开仓价格 NumericSeries LastPrice; // 最后一次开仓价格 Numeric AddSet(30); // 加仓设置 Numeric SubSet(30); // 减仓设置 Bool FirstEntryCon; // 首次开仓条件Begin FirstEntryCon = ... MinPoint = MinMove*PriceScale; If(MarketPosition==0) { If(FirstEntryCon) { firstPrice = Open; LastPrice = firstPrice; Buy(2,firstPrice); } }else If(MarketPosition==1) // 有多仓的情况 { While(CurrentEntries < 4 High >= LastPrice + AddSet*MinPoint) // 加仓 { LastPrice = LastPrice + AddSet*MinPoint; if(Open > LastPrice) LastPrice = Open; Buy(1,LastPrice); } While(CurrentEntries > 0 Low <= firstPrice - SubSet*MinPoint) // 减仓 { firstPrice = firstPrice - SubSet*MinPoint; if(Open < firstPrice) firstPrice = Open; Sell(1,firstPrice); } } ...End注意事项:
- 因无法确认开仓Bar最高/低价和开仓价的先后顺序,忽略开仓Bar的加减仓处理。
- 如果某个Bar最高/低价相差很大,可能出现加仓减仓同时满足的情况,这种情况下需要切换到更小的周期进行交易,或者扩大加仓/减仓幅度设置。
多品种交易模板以常用的双均线系统为例,对主图商品和叠加商品分别进行交易。 Params Numeric FastLength1(5); // Data0的短周期参数 Numeric SlowLength1(20); // Data0的长周期参数 Numeric FastLength2(5); // Data1的短周期参数 Numeric SlowLength2(20); // Data1的长周期参数Vars NumericSeries AvgValue11; NumericSeries AvgValue12; NumericSeries AvgValue21; NumericSeries AvgValue22;Begin AvgValue11 = AverageFC(Data0.Close,FastLength1); AvgValue12 = AverageFC(Data0.Close,SlowLength1); AvgValue21 = AverageFC(Data1.Close,FastLength2); AvgValue22 = AverageFC(Data1.Close,SlowLength2); If(Data0.MarketPosition <>1 AvgValue11[1] > AvgValue12[1]) { Data0.Buy(1,Data0.Open); } If(Data0.MarketPosition <>-1 AvgValue11[1] < AvgValue12[1]) { Data0.SellShort(1,Data0.Open); } If(Data1.MarketPosition <>1 AvgValue21[1] > AvgValue22[1]) { Data1.Buy(1,Data1.Open); } If(Data1.MarketPosition <>-1 AvgValue21[1] < AvgValue22[1]) { Data1.SellShort(1,Data1.Open); }End注意事项:
- 针对不同的商品的数据进行计算或交易,需通过Data#这样的方式添加前缀,Data0可与省略不写。
- Data#的顺序和超级图表中商品设置界面的顺序相同,必须要叠加足够的商品才能保证代码正常执行。
集合竞价数据过滤集合竞价时,会产生一个Tick,这个Tick会驱动超级图表计算交易策略,如果条件满足,则会马上发送委托单,但此时交易所并未开市,就会产生废单,为了处理这种情况,可以采取下面方法: Begin If(BarStatus==2 Time==0.090000 High==Low) return; // 第一种写法 If(BarStatus==2 Time==0.090000 CurrentTime <= 0.090000) return; // 第二种写法 ...End注意事项:
- 本例是以国内商品期货交易所开市时间举例,股指期货或其他市场需调整写法。
- 若按第一种写法,当商品的高低价不产生变化时,会忽略这些Tick,即使是已经开市;第二种写法需保证本机的时间准确。
收盘平仓收盘平仓分为两部分,一部分负责处理历史测试,一部分负责处理实时交易。在测试时我们可以以每天的收盘价平仓,在实时交易时我们选择14:59分平仓。 Begin ... If((Date[-1]!=InvalidInteger Date!=Date[-1])||(Date[-1]==InvalidInteger Date < CurrentDate)) { Sell(0,Close); BuyToCover(0,Close); }Else If(Date==CurrentDate Time==0.1455 CurrentTime>=0.1459) { Sell(0,Close); BuyToCover(0,Close); } ...End注意事项:
- 本例是以国内商品期货交易所收市时间举例,股指期货或其他市场需调整写法。
- 本例是针对5分钟周期的收盘平仓所写,针对不同的周期需改写为合适的最后Bar时间。
A函数下单撤单和全局变量操作本例在每天收盘前N分钟的时候自动撤掉超级图表中商品的挂单,并全部平仓。通过A_SendOrder进行下单,A_DeleteOrder进行撤单,并使用全局变量记录Tick计数和撤单标志。 Params Numeric offSet(1); // 委托价格偏移,为了保证成交 Numeric BeforeMins(5); // 收盘前几分钟开始操作Vars Numeric tempPos; // 仓位 Numeric DeleteOrderTickCounter; Numeric HasSendOrder(0);Begin If(BarStatus == 0) { DeleteOrderTickCounter = 9999; HasSendOrder = 0; SetGlobalVar(0,DeleteOrderTickCounter); SetGlobalVar(1,HasSendOrder); }Else { DeleteOrderTickCounter = GetGlobalVar(0); HasSendOrder = GetGlobalVar(1); } If(CurrentTime > (0.1459 - 0.0001*(BeforeMins-1)) BarStatus == 2 HasSendOrder == 0) { If(Data0.Close != InvalidNumeric Data0.A_GetOpenOrderCount()>0) // 商品0全部撤单 { Data0.A_DeleteOrder(); DeleteOrderTickCounter = 1; } If(Data1.Close != InvalidNumeric Data1.A_GetOpenOrderCount()>0) // 商品1全部撤单 { Data1.A_DeleteOrder(); DeleteOrderTickCounter = 1; } If(Data2.Close != InvalidNumeric Data2.A_GetOpenOrderCount()>0) // 商品2全部撤单 { Data2.A_DeleteOrder(); DeleteOrderTickCounter = 1; } DeleteOrderTickCounter = DeleteOrderTickCounter + 1; SetGlobalVar(0,DeleteOrderTickCounter); If(DeleteOrderTickCounter < 5) Return; // 撤单后需要延迟几个Tick才平仓 tempPos = Data0.A_BuyPosition(); If(tempPos > 0) // 平多单 { Data0.A_SendOrder(Enum_Sell,Enum_Exit,tempPos,Data0.Q_BidPrice-offSet*Data0.MinMove*Data0.PriceScale); } tempPos = Data0.A_SellPosition(); If(tempPos > 0) //平空单 { Data0.A_SendOrder(Enum_Buy,Enum_Exit,tempPos,Data0.Q_AskPrice+offSet*Data0.MinMove*Data0.PriceScale); } tempPos = Data1.A_BuyPosition; If(tempPos > 0) // 平多单 { Data1.A_SendOrder(Enum_Sell,Enum_Exit,tempPos,Data1.Q_BidPrice-offSet*Data1.MinMove*Data1.PriceScale); } tempPos = Data1.A_SellPosition; If(tempPos > 0) //平空单 { Data1.A_SendOrder(Enum_Buy,Enum_Exit,tempPos,Data1.Q_AskPrice+offSet*Data1.MinMove*Data1.PriceScale); } tempPos = Data2.A_BuyPosition; If(tempPos > 0) // 平多单 { Data2.A_SendOrder(Enum_Sell,Enum_Exit,tempPos,Data2.Q_BidPrice-offSet*Data2.MinMove*Data2.PriceScale); } tempPos = Data2.A_SellPosition; If(tempPos > 0) //平空单 { Data2.A_SendOrder(Enum_Buy,Enum_Exit,tempPos,Data2.Q_AskPrice+offSet*Data2.MinMove*Data2.PriceScale); } HasSendOrder = 1; SetGlobalVar(1,HasSendOrder); }End注意事项:
- 本例是以国内商品期货交易所收市时间举例,股指期货或其他市场需调整写法。
- 本例假设撤单后5个Tick委托状态能同步成功,实际情况中因网络延时等原因并不一定能够保证成功。
数据库读写本例以5分钟周期调用日线指标数据举例讲解具体应用。 操作步骤如下:
- 新建一个工作区,包含上下两个图表窗体,上面选择日线周期,下面选择5分钟周期。
- 新建一个公式应用,命名为MyDayMA。编译成功后插入日线图表中。详细代码如下:
Params Numeric length(10);Vars Numeric MA; string strkey; string strValue;Begin MA = AverageFC(Close,length); strKey = DateToString(Date); strValue = Text(MA); SetTBProfileString("DayMA",strKey,strValue); PlotNumeric("MA",MA);End
- 新建一个公式应用,My5MinMA。编译成功后插入5分钟图表中,详细代码如下:
Vars NumericSeries DayMAValue; string strKey; string strValue;Begin strKey = DateToString(Date); strValue = GetTBProfileString("DayMA",strKey); If(strValue != InvalidString) { DayMAValue = Value(strValue); }Else { DayMAValue = DayMAValue[1]; } PlotNumeric("DayMA",DayMAValue);End
- 上面的公式实际使用了未来数据,用来写技术分析是可以的,但用来进行自动交易就会出问题,为了更准确合理的使用跨周期数据,我们应该稍作修改,代码如下:
Vars NumericSeries DayMAValue; StringSeries strKey; string strValue;Begin If(Date!=Date[1]) { strKey = DateToString(Date[1]); }Else { strKey = strKey[1]; } strValue = GetTBProfileString("DayMA",strKey); If(strValue != InvalidString) { DayMAValue = Value(strValue); }Else { DayMAValue = DayMAValue[1]; } PlotNumeric("DayMA",DayMAValue);End