TB交易策略的代碼寫(xiě)法
欄目:開(kāi)拓者TB教學(xué) 來(lái)源:TradeBlazer使用指南 最后更新時(shí)間:2026/1/24 1:25:50

交易策略的代碼寫(xiě)法會(huì)因?yàn)榻灰姿枷爰熬幊塘?xí)慣因人而異,在此按常用的功能點(diǎn)列出代碼示例,用戶可根據(jù)自己的需要選擇對(duì)應(yīng)的代碼進(jìn)行組合。
止贏止損 跟蹤止損 加倉(cāng)減倉(cāng) 多品種交易
集合競(jìng)價(jià)數(shù)據(jù)過(guò)濾 收盤(pán)平倉(cāng) A函數(shù)下單撤單和全局變量操作 數(shù)據(jù)庫(kù)讀寫(xiě)
止贏止損
模板以止贏30跳,止損20跳為例,也可以轉(zhuǎn)換為開(kāi)倉(cāng)價(jià)格的百分比值,或其任何設(shè)置的變量進(jìn)行處理。
Vars
Numeric MinPoint; // 一個(gè)最小變動(dòng)單位,也就是一跳
Numeric MyEntryPrice; // 開(kāi)倉(cāng)價(jià)格,本例是開(kāi)倉(cāng)均價(jià),也可根據(jù)需要設(shè)置為某次入場(chǎng)的價(jià)格
Numeric TakeProfitSet(30); // 止贏設(shè)置
Numeric StopLossSet(20); // 止損設(shè)置
Numeric MyExitPrice; // 平倉(cāng)價(jià)格
Begin
...
MinPoint = MinMove*PriceScale;
MyEntryPrice = AvgEntryPrice;
If(MarketPosition==1) // 有多倉(cāng)的情況
{
If(High >= MyEntryPrice + TakeProfitSet*MinPoint) // 止贏條件表達(dá)式
{
MyExitPrice = MyEntryPrice + TakeProfitSet*MinPoint;
If(Open > MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
Sell(0,MyExitPrice);
}else if(Low <= MyEntryPrice - StopLossSet*MinPoint)//
止損條件表達(dá)式
{
MyExitPrice = MyEntryPrice - StopLossSet*MinPoint;
If(Open < MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
Sell(0,MyExitPrice);
}
}else if(MarketPosition==-1) // 有空倉(cāng)的情況
{
If(Low <= MyEntryPrice - TakeProfitSet*MinPoint) // 止贏條件表達(dá)式
{
MyExitPrice = MyEntryPrice - TakeProfitSet*MinPoint;
If(Open < MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
BuyToCover(0,MyExitPrice);
}else if(High >= MyEntryPrice + StopLossSet*MinPoint)//
止損條件表達(dá)式
{
MyExitPrice = MyEntryPrice + StopLossSet*MinPoint;
If(Open > MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
BuyToCover(0,MyExitPrice);
}
}
...
End
注意事項(xiàng):
因無(wú)法確認(rèn)開(kāi)倉(cāng)Bar最高/低價(jià)和開(kāi)倉(cāng)價(jià)的先后順序,因此以上寫(xiě)法一般忽略開(kāi)倉(cāng)Bar的處理。
如果某個(gè)Bar最高/低價(jià)相差很大,可能出現(xiàn)止贏止損同時(shí)滿足的情況,這種情況下需要切換到更小的周期進(jìn)行交易,或者擴(kuò)大止贏/損幅度。
跟蹤止損
跟蹤止損有很多種方式,本模板的規(guī)則如下:當(dāng)盈利達(dá)到50跳之后啟動(dòng)第一級(jí)跟蹤止損,止損的回撤值為30跳,當(dāng)盈利達(dá)到80跳之后啟動(dòng)第二級(jí)的跟蹤止損,止損的回撤值為20跳。您也可以將這些固定的設(shè)置修改為盈利百分比,或者是某個(gè)價(jià)格的百分比。
Vars
Numeric MinPoint; // 一個(gè)最小變動(dòng)單位,也就是一跳
Numeric MyEntryPrice; // 開(kāi)倉(cāng)價(jià)格,本例是開(kāi)倉(cāng)均價(jià),也可根據(jù)需要設(shè)置為某次入場(chǎng)的價(jià)格
Numeric TrailingStart1(50); // 跟蹤止損啟動(dòng)設(shè)置1
Numeric TrailingStart2(80); // 跟蹤止損啟動(dòng)設(shè)置2
Numeric TrailingStop1(30); // 跟蹤止損設(shè)置1
Numeric TrailingStop2(20); // 跟蹤止損設(shè)置2
Numeric StopLossSet(50); // 止損設(shè)置
Numeric MyExitPrice; // 平倉(cāng)價(jià)格
NumericSeries HighestAfterEntry; // 開(kāi)倉(cāng)后出現(xiàn)的最高價(jià)
NumericSeries LowestAfterEntry; // 開(kāi)倉(cāng)后出現(xiàn)的最低價(jià)
Begin
...
If(BarsSinceentry == 0)
{
HighestAfterEntry = Close;
LowestAfterEntry = Close;
If(MarketPosition <> 0)
{
HighestAfterEntry = Max(HighestAfterEntry,AvgEntryPrice); //
開(kāi)倉(cāng)的Bar,將開(kāi)倉(cāng)價(jià)和當(dāng)時(shí)的收盤(pán)價(jià)的較大值保留到HighestAfterEntry
LowestAfterEntry = Min(LowestAfterEntry,AvgEntryPrice); //
開(kāi)倉(cāng)的Bar,將開(kāi)倉(cāng)價(jià)和當(dāng)時(shí)的收盤(pán)價(jià)的較小值保留到LowestAfterEntry
}
}else
{
HighestAfterEntry = Max(HighestAfterEntry,High); //
記錄下當(dāng)前Bar的最高點(diǎn),用于下一個(gè)Bar的跟蹤止損判斷
LowestAfterEntry = Min(LowestAfterEntry,Low); //
記錄下當(dāng)前Bar的最低點(diǎn),用于下一個(gè)Bar的跟蹤止損判斷
}
Commentary("HighestAfterEntry="+Text(HighestAfterEntry));
Commentary("LowestAfterEntry="+Text(LowestAfterEntry));
MinPoint = MinMove*PriceScale;
MyEntryPrice = AvgEntryPrice;
If(MarketPosition==1) // 有多倉(cāng)的情況
{
If(HighestAfterEntry[1] >= MyEntryPrice + TrailingStart2*MinPoint)
// 第二級(jí)跟蹤止損的條件表達(dá)式
{
If(Low <= HighestAfterEntry[1] - TrailingStop2*MinPoint)
{
MyExitPrice = HighestAfterEntry[1] - TrailingStop2*MinPoint;
If(Open < MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
Sell(0,MyExitPrice);
}
}else if(HighestAfterEntry[1] >= MyEntryPrice +
TrailingStart1*MinPoint)// 第一級(jí)跟蹤止損的條件表達(dá)式
{
If(Low <= HighestAfterEntry[1] - TrailingStop1*MinPoint)
{
MyExitPrice = HighestAfterEntry[1] - TrailingStop1*MinPoint;
If(Open < MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
Sell(0,MyExitPrice);
}
}else if(Low <= MyEntryPrice - StopLossSet*MinPoint)//可以在這里寫(xiě)上初始的止損處理
{
MyExitPrice = MyEntryPrice - StopLossSet*MinPoint;
If(Open < MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
Sell(0,MyExitPrice);
}
}else if(MarketPosition==-1) // 有空倉(cāng)的情況
{
If(LowestAfterEntry[1] <= MyEntryPrice - TrailingStart2*MinPoint)
// 第二級(jí)跟蹤止損的條件表達(dá)式
{
If(High >= LowestAfterEntry[1] + TrailingStop2*MinPoint)
{
MyExitPrice = LowestAfterEntry[1] + TrailingStop2*MinPoint;
If(Open > MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
BuyToCover(0,MyExitPrice);
}
}else if(LowestAfterEntry[1] <= MyEntryPrice -
TrailingStart1*MinPoint)// 第一級(jí)跟蹤止損的條件表達(dá)式
{
If(High >= LowestAfterEntry[1] + TrailingStop1*MinPoint)
{
MyExitPrice = LowestAfterEntry[1] + TrailingStop1*MinPoint;
If(Open > MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
BuyToCover(0,MyExitPrice);
}
}else If(High >= MyEntryPrice + StopLossSet*MinPoint)//可以在這里寫(xiě)上初始的止損處理
{
MyExitPrice = MyEntryPrice + StopLossSet*MinPoint;
If(Open > MyExitPrice) MyExitPrice = Open; //
如果該Bar開(kāi)盤(pán)價(jià)有跳空觸發(fā),則用開(kāi)盤(pán)價(jià)代替
BuyToCover(0,MyExitPrice);
}
}
...
End
注意事項(xiàng):
因無(wú)法確認(rèn)開(kāi)倉(cāng)Bar最高/低價(jià)和開(kāi)倉(cāng)價(jià)的先后順序,因此以上寫(xiě)法一般忽略開(kāi)倉(cāng)Bar的處理。
如果某個(gè)Bar最高/低價(jià)相差很大,可能出現(xiàn)創(chuàng)新高之后跟蹤止損的情況,但系統(tǒng)無(wú)法確認(rèn)最高價(jià)和最低價(jià)的先后順序,因此本模板只用前一個(gè)Bar的最高/低價(jià)計(jì)算最大贏利位置。
加倉(cāng)減倉(cāng)
本例僅以做多為例,做空類(lèi)似。模板以首次開(kāi)倉(cāng)2手后每贏利30跳加倉(cāng)一次,每次1手,最多加倉(cāng)3次;開(kāi)倉(cāng)后每虧損30跳減倉(cāng)1手。也可以轉(zhuǎn)換為開(kāi)倉(cāng)價(jià)格的百分比值,或波動(dòng)率的百分比等其任何設(shè)置的變量進(jìn)行處理。
Vars
Numeric MinPoint; // 一個(gè)最小變動(dòng)單位,也就是一跳
NumericSeries firstPrice; // 第一次開(kāi)倉(cāng)價(jià)格
NumericSeries LastPrice; // 最后一次開(kāi)倉(cāng)價(jià)格
Numeric AddSet(30); // 加倉(cāng)設(shè)置
Numeric SubSet(30); // 減倉(cāng)設(shè)置
Bool FirstEntryCon; // 首次開(kāi)倉(cāng)條件
Begin
FirstEntryCon = ...
MinPoint = MinMove*PriceScale;
If(MarketPosition==0)
{
If(FirstEntryCon)
{
firstPrice = Open;
LastPrice = firstPrice;
Buy(2,firstPrice);
}
}else If(MarketPosition==1) // 有多倉(cāng)的情況
{
While(CurrentEntries < 4 && High >= LastPrice + AddSet*MinPoint)
// 加倉(cāng)
{
LastPrice = LastPrice + AddSet*MinPoint;
if(Open > LastPrice) LastPrice = Open;
Buy(1,LastPrice);
}
While(CurrentEntries > 0 && Low <= firstPrice - SubSet*MinPoint)
// 減倉(cāng)
{
firstPrice = firstPrice - SubSet*MinPoint;
if(Open < firstPrice) firstPrice = Open;
Sell(1,firstPrice);
}
}
...
End
注意事項(xiàng):
因無(wú)法確認(rèn)開(kāi)倉(cāng)Bar最高/低價(jià)和開(kāi)倉(cāng)價(jià)的先后順序,忽略開(kāi)倉(cāng)Bar的加減倉(cāng)處理。
如果某個(gè)Bar最高/低價(jià)相差很大,可能出現(xiàn)加倉(cāng)減倉(cāng)同時(shí)滿足的情況,這種情況下需要切換到更小的周期進(jìn)行交易,或者擴(kuò)大加倉(cāng)/減倉(cāng)幅度設(shè)置。
多品種交易
模板以常用的雙均線系統(tǒng)為例,對(duì)主圖商品和疊加商品分別進(jìn)行交易。
Params
Numeric FastLength1(5); // Data0的短周期參數(shù)
Numeric SlowLength1(20); // Data0的長(zhǎng)周期參數(shù)
Numeric FastLength2(5); // Data1的短周期參數(shù)
Numeric SlowLength2(20); // Data1的長(zhǎng)周期參數(shù)
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
注意事項(xiàng):
針對(duì)不同的商品的數(shù)據(jù)進(jìn)行計(jì)算或交易,需通過(guò)Data#這樣的方式添加前綴,Data0可與省略不寫(xiě)。
Data#的順序和超級(jí)圖表中商品設(shè)置界面的順序相同,必須要疊加足夠的商品才能保證代碼正常執(zhí)行。
集合競(jìng)價(jià)數(shù)據(jù)過(guò)濾
集合競(jìng)價(jià)時(shí),會(huì)產(chǎn)生一個(gè)Tick,這個(gè)Tick會(huì)驅(qū)動(dòng)超級(jí)圖表計(jì)算交易策略,如果條件滿足,則會(huì)馬上發(fā)送委托單,但此時(shí)交易所并未開(kāi)市,就會(huì)產(chǎn)生廢單,為了處理這種情況,可以采取下面方法:
Begin
If(BarStatus==2 && Time==0.090000 && High==Low) return; //
第一種寫(xiě)法
If(BarStatus==2 && Time==0.090000 && CurrentTime <=
0.090000) return; // 第二種寫(xiě)法
...
End
注意事項(xiàng):
本例是以國(guó)內(nèi)商品期貨交易所開(kāi)市時(shí)間舉例,股指期貨或其他市場(chǎng)需調(diào)整寫(xiě)法。
若按第一種寫(xiě)法,當(dāng)商品的高低價(jià)不產(chǎn)生變化時(shí),會(huì)忽略這些Tick,即使是已經(jīng)開(kāi)市;第二種寫(xiě)法需保證本機(jī)的時(shí)間準(zhǔn)確。
收盤(pán)平倉(cāng)
收盤(pán)平倉(cāng)分為兩部分,一部分負(fù)責(zé)處理歷史測(cè)試,一部分負(fù)責(zé)處理實(shí)時(shí)交易。在測(cè)試時(shí)我們可以以每天的收盤(pán)價(jià)平倉(cāng),在實(shí)時(shí)交易時(shí)我們選擇14:59分平倉(cāng)。
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
注意事項(xiàng):
本例是以國(guó)內(nèi)商品期貨交易所收市時(shí)間舉例,股指期貨或其他市場(chǎng)需調(diào)整寫(xiě)法。
本例是針對(duì)5分鐘周期的收盤(pán)平倉(cāng)所寫(xiě),針對(duì)不同的周期需改寫(xiě)為合適的最后Bar時(shí)間。
A函數(shù)下單撤單和全局變量操作
本例在每天收盤(pán)前N分鐘的時(shí)候自動(dòng)撤掉超級(jí)圖表中商品的掛單,并全部平倉(cāng)。通過(guò)A_SendOrder進(jìn)行下單,A_DeleteOrder進(jìn)行撤單,并使用全局變量記錄Tick計(jì)數(shù)和撤單標(biāo)志。
Params
Numeric offSet(1); // 委托價(jià)格偏移,為了保證成交
Numeric BeforeMins(5); // 收盤(pán)前幾分鐘開(kāi)始操作
Vars
Numeric tempPos; // 倉(cāng)位
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; // 撤單后需要延遲幾個(gè)Tick才平倉(cāng)
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
注意事項(xiàng):
本例是以國(guó)內(nèi)商品期貨交易所收市時(shí)間舉例,股指期貨或其他市場(chǎng)需調(diào)整寫(xiě)法。
本例假設(shè)撤單后5個(gè)Tick委托狀態(tài)能同步成功,實(shí)際情況中因網(wǎng)絡(luò)延時(shí)等原因并不一定能夠保證成功。
數(shù)據(jù)庫(kù)讀寫(xiě)
本例以5分鐘周期調(diào)用日線指標(biāo)數(shù)據(jù)舉例講解具體應(yīng)用。
操作步驟如下:
新建一個(gè)工作區(qū),包含上下兩個(gè)圖表窗體,上面選擇日線周期,下面選擇5分鐘周期。
新建一個(gè)公式應(yīng)用,命名為MyDayMA。編譯成功后插入日線圖表中。詳細(xì)代碼如下:
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
新建一個(gè)公式應(yīng)用,My5MinMA。編譯成功后插入5分鐘圖表中,詳細(xì)代碼如下:
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
上面的公式實(shí)際使用了未來(lái)數(shù)據(jù),用來(lái)寫(xiě)技術(shù)分析是可以的,但用來(lái)進(jìn)行自動(dòng)交易就會(huì)出問(wèn)題,為了更準(zhǔn)確合理的使用跨周期數(shù)據(jù),我們應(yīng)該稍作修改,代碼如下:
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
相關(guān)內(nèi)容:
TB[用戶]內(nèi)建函數(shù)說(shuō)明表
TB程序中數(shù)據(jù)的回溯
TB支持的三種基本數(shù)據(jù)類(lèi)型
TB公式的賦值語(yǔ)句
TB交易策略的性能測(cè)試
開(kāi)拓者TB程序的控制語(yǔ)句
TB公式基礎(chǔ)之用戶函數(shù) |
|