COCO研究院

 找回密碼
 註冊
搜索
樓主: kilroy

[教學] [分享] 用AB踏入外期程式交易

  [複製鏈接]
發表於 14-6-14 21:35 | 顯示全部樓層
kilroy 發表於 14-6-14 20:59
Hi,

日圓

感謝您的熱心分享~~
發表於 14-6-15 19:36 | 顯示全部樓層
K大您好昨天在做MC的功課時
看到一句話"每根K棒結束都執行程式一次"
因此想請教一個關於回測的問題
AB是否也是如此,在K棒結束後執行程式一次
判斷是否有進出場條件
用以下的程式當範例

MA5_P1 = Ref( MA( C, 5 ), -1 );
MA5_P2 = Ref( MA( C, 5 ), -2 );

Cond_MA5_Buy = MA5_P1 > MA5_P2;
Cond_MA5_Sell = MA5_P1 < MA5_P2;

Cross5_Buy =  Cross ( Ref( C, -1 ), MA5_P1 );
Cross5_Sell = Cross ( MA5_P1, Ref( C, -1 ) );

Buy = Cond_MA5_Buy AND Cross5_Buy ;
Sell = Cross5_Sell;
Short = Cond_MA5_Sell AND Cross5_Sell ;
Cover = Cond_MA5_Buy ;

Buy = ExRem( Buy, Short );
Short = ExRem( Short, Buy );
Cover = ExRem( Cover , Sell );
Sell = ExRem( Sell , Cover );

BuyPrice = CoverPrice = O;
ShortPrice = SellPrice = O;




以上的程式
再回測上不會有問題
但在實際SCAN上
由於是K棒結束後才去執行判斷是否進場
假設
當K棒結束後BUY的條件成立
以該K棒OPEN價格進場
由於K棒已經結束了
除非K棒CLOSE價格等於或小於OPEN價格
不然根本買不到
也就是即使SCAN時有條件成立
但實際上很可能無法成交

不知我的理解對不對?!

若真如此
以上面這段範例
應該如何修改才對

感謝您的回覆
謝謝


 樓主| 發表於 14-6-15 21:37 | 顯示全部樓層
skyler 發表於 14-6-15 19:36
K大您好昨天在做MC的功課時
看到一句話"每根K棒結束都執行程式一次"
因此想請教一個關於回測的問題

在條件裡加上這行
barcomplete = BarIndex() < LastValue(BarIndex());

或是 buy=ref(...,-1);

評分

參與人數 1金錢 +2 收起 理由
skyler + 2 感謝分享

查看全部評分

發表於 14-6-15 21:59 | 顯示全部樓層
所以
這段程式碼在回測是OK
但實際執行上會有問題
我的理解上是沒有錯的嗎?
 樓主| 發表於 14-6-15 22:47 | 顯示全部樓層
skyler 發表於 14-6-15 21:59
所以
這段程式碼在回測是OK
但實際執行上會有問題

Hi,

這段 AFL 裡

回測沒問題

SCAN 模式下,會在當根K開始時判斷是否符合買賣條件

符合的話會送單出去了

---
順帶一提

用 scan 的方式

不能用 buy=flip(buy,sell); 這類的語法



參考看看了
發表於 14-6-15 22:52 | 顯示全部樓層
本帖最後由 skyler 於 14-6-15 22:53 編輯
kilroy 發表於 14-6-15 22:47
Hi,

這段 AFL 裡

所以會在當根K棒開始時判斷
這樣子的話
假設計算速度很快當BUY訊號成立時
那這段AFL下出去以OPEN價的多單
應該都會成立囉?
(PS:不管滑價問題)

所以這就跟MC 是在K棒結束後才判斷
是有所不同囉?

另外我不太懂這個
buy=flip(buy,sell);
的含意?

感謝指導~


 樓主| 發表於 14-6-15 23:15 | 顯示全部樓層
本帖最後由 kilroy 於 14-6-15 23:16 編輯
skyler 發表於 14-6-15 22:52
所以會在當根K棒開始時判斷
這樣子的話
假設計算速度很快當BUY訊號成立時

Hi,

可以丟 open 價的 limit 單

但不能保證一定會成交,因為你的單子還得排隊

scan 的方式和 chart 的方式,當根K開盤符合條件後丟市價單,可以在兩點以內成交

可是像 HO(熱燃油) 之類的商品,掛單(ask/bid)較散的時候,成交的價位會與你回測的價位有較大的差距

---
SCAN 會依照原本回測的位置去丟單

ex. 回測 6/04 開盤丟單,那你 SCAN recent 1 bar 是在當天(6/4) 會有訊號

假設這個訊號是多單且持續 (open long) 到6/16

可是 6/16 並不會再出現一次多單的訊號

而 flip 會延續這個 open long 的訊號,並在 6/16 再次丟出多單 order

簡單來說 flip 會在當根K依照 open long/short 的部位再次送單

---
若使用在 chart 的方式,就不會有這個問題

詳細的使用可以參考一些範例

大概會用到的用途是類似

same bar entry/exit

但這類用法很容易有 bug 而且也不好抓


所以不建議使用 flip


參考看看了




發表於 14-6-16 00:10 | 顯示全部樓層
kilroy 發表於 14-6-1 22:49
Hi,

1.

謝謝K 大, 過去兩個星期 我已經不斷嘗試了無數次, K大的語法都用上, 但都無法做到我希望的結果
請大大再幫忙, 看看我的語法要怎樣修改才可以:

1. 設定 "Sell" 只會出現在 "Buy" 成立了之後
2. 把 trailling stop 的語法寫進策略裡


假設以下是一個10分k 策略




AutoTradingParam = True;         //ParamToggle("AutoTrading","Off|On",0);
SubmitOrders = True;             //ParamToggle("Create or Transmit","Create Only|Create and Transmit",False);
Tracing = False;

BaseRiskPcnt = 1.00;    // Percent of account risk per trade
AccountCutout = 75000;  // Stop trading if account falls to $X

// Function to provide voice warning whenever any new trades are created

function SayNotTooOften( text, Minperiod )
{
   elapsed=GetPerformanceCounter()/1000;
   Lastelapsed = Nz( StaticVarGet("lastsaytime") );

   if( elapsed - Lastelapsed > Minperiod )
   {
     StaticVarSet("lastsaytime", elapsed );
     Say( text );
   }
}

// Interactive Brokers ticker symbols may have unwanted characters for our static variable names. Remove them.

ABName = StrMid(Name(),0,3) + StrMid(Name(),4,3);
IBName = Name();
       
AutoTrading = StaticVarGet("AutoTrading"+ABName);
if( IsNull( AutoTrading ) )
        StaticVarSet("AutoTrading"+ABName,0);

if ( AutoTrading==0 && AutoTradingParam )
{
  // About to start AutoTrading after it's been off, so clear all order statuses.
        StaticVarSetText("OrderID"+ABName,"");
        StaticVarSetText("OrderIDLMT"+ABName,"");
        StaticVarSetText("OrderIDSTP"+ABName,"");
        StaticVarSetText("OrderStatus"+ABName,"");
        StaticVarSetText("OrderLMTStatus"+ABName,"");
        StaticVarSetText("OrderStatusSTP"+ABName,"");
}
if ( AutoTrading && AutoTradingParam==0 )
{
  // About to stop AutoTrading after it's been on, so clear all order statuses.
        StaticVarSetText("OrderID"+ABName,"");
        StaticVarSetText("OrderIDLMT"+ABName,"");
        StaticVarSetText("OrderIDSTP"+ABName,"");
        StaticVarSetText("OrderStatus"+ABName,"");
        StaticVarSetText("OrderLMTStatus"+ABName,"");
        StaticVarSetText("OrderStatusSTP"+ABName,"");
}

if (AutoTradingParam)
        StaticVarSet("AutoTrading"+ABName,1);
else  
        StaticVarSet("AutoTrading"+ABName,0);

AutoTrading = StaticVarGet("AutoTrading"+ABName);

Filename         = _DEFAULT_NAME();

// Your trading conditions here////////////////////////////////////////////////



TimeFrameSet( 30 * in1Minute );
BuySignal1 = C < MA (C, 15);
TimeFrameRestore();

BuySignal = C> Ref(C,-1);
sellSignal = Ref(C,-1) >C;
TimeFrameRestore();

Buy = BuySignal & TimeFrameExpand(BuySignal1 , N*in1Minute) ;
Sell =sellSignal  & TimeFrameExpand(BuySignal2 , N*in1Minute);
Short = Cover=0;


// Following variables for exits are mostly for backtesting. Not all are used in Autotrading.

ISLARC=3;  // Initial Stop Loss multiplier x ATR. Set as appropriate for your trading rules.
ISL=ATR(20)*ISLARC;

TSLARC=ISLARC;  // Trailing Stop Loss multiplier x ATR. Set as appropriate for your trading rules.
TSL=ATR(20)*TSLARC;

PSLARC=10000;  // Take Profit multiplier x ATR. Set as appropriate for your trading rules.
PSL=ATR(20)*PSLARC;

nBars = 15;  // Exit after n Bars. Set as appropriate for your trading rules.

ShortISLPrice=ShortPrice+Ref(ISL,-1);
ShortPSLPrice=ShortPrice-Ref(PSL,-1);
BuyISLPrice=BuyPrice-Ref(ISL,-1);
BuyPSLPrice=BuyPrice+Ref(ISL,-1);////////******************

// Set some variables for the right edge of the chart for the Auto-Trading code.

LastShortPrice=LastValue(ShortPrice);
LastBuyPrice=LastValue(BuyPrice);
LastShortISLPrice=LastValue(ShortISLPrice);
LastShortPSLPrice=LastValue(ShortPSLPrice);
LastBuyISLPrice=LastValue(BuyISLPrice);
LastBuyPSLPrice=LastValue(BuyPSLPrice);////////////////*******************;
LastATR=LastValue(Ref(ATR(20),-1));


/////////////////// Automation Code //////////////////

// First check if we've just started a new bar. THIS CODE RELIES ON PREFERENCES/INTRADAY SET TO START OF INTERVAL.

PrevDT = StaticVarGet("DateTime"+ABName);
DT = LastValue(DateTime());
NewBar = DT != PrevDT;                        
StaticVarSet("DateTime"+ABName,DT);

if( NewBar )
{
    // Clear all status so we can place a new order on each bar. Later, the status variables are checked to ensure
    //     that we place no more than 1 order on each bar.

    StaticVarSetText("OrderID"+ABName,"");
    StaticVarSetText("OrderIDLMT"+ABName,"");
    StaticVarSetText("OrderIDSTP"+ABName,"");
    StaticVarSetText("OrderStatus"+ABName,"");
    StaticVarSetText("OrderLMTStatus"+ABName,"");
    StaticVarSetText("OrderStatusSTP"+ABName,"");
}

LastBuy = LastValue(Buy);
LastSell = LastValue(Sell);
LastShort = LastValue(Short);

Filter=Buy OR Sell;

IBPosSize=0;

ibc = GetTradingInterface("IB");
IBcStatus = ibc.IsConnected();

IBcStatusString = WriteIf(IBCStatus==0,"TWS Not Found",
                                                WriteIf(IBCStatus==1,"Connecting to TWS",
                                                        WriteIf(IBCStatus==2,"TWS OK",
                                                                WriteIf(IBCStatus==3,"TWS OK (msgs)",""))));

// Work out how much money there is and adjust risk size

CashBalanceStr = ibc.GetAccountValue("NetLiquidationByCurrency");
if (CashBalanceStr == "")
    CashBalance = 0;
else
    CashBalance = StrToNum(CashBalanceStr);

// Note CashBalance is in AUD for my account, so following calculations are all in AUD.
// If trading instruments denominated in multiple currencies, e.g. FX, you will need to adjust this code.
//     It is possible to dynamically lookup the IB FX price
//     but too extensive for me to include the code here

PositionRisk = BaseRiskPcnt/100*CashBalance;
PositionSize = PositionRisk / Ref(ISL,-1);
IBOrderSize = int(LastValue(PositionSize)/10000)*10000;  // Round to nearest $10k - designed for FX ************

OldOrderID = StaticVarGetText("OrderID"+ABName);
if (AutoTrading == 0 && OldORderID == "" && (LastBuy || LastSell))
{
    // If there would have been an order during Autotrading, then create a dummy OID to test all other code paths
    // e.g. logging, explore output etc.
    StaticVarSetText("OrderID"+ABName,"DUMMY");
}

if( IBcStatus AND AutoTrading AND (CashBalance > AccountCutout))
{
    OrderID = StaticVarGetText("OrderID"+ABName);
    OrderIDLMT = StaticVarGetText("OrderIDLMT"+ABName);
    OrderIDSTP = StaticVarGetText("OrderIDSTP"+ABName);

    IBPosSize = ibc.GetPositionSize( IBName );
        // Only enter once the price moves in my desired direction, otherwise wait until next run of the exploration
        //     and check again, and again., ...
    if( LastBuy AND OrderID == "" )  
    {
        OID = ibc.PlaceOrder( IBName, "Buy", 1, "MKT", 0, TickSize,
                              "DAY", submitorders, TickSize/0.0001, "outsideRTH" );
        // _TRACE("# Pos: 0, PrevOID: "+OrderID+", Buy 1, NewOID: "+OID);


        for (dummy=0; dummy<40; dummy++)
            ibc.Sleep(50);  //Usually takes up to about a second for TWS to get acknowledgement from IB
        StaticVarSetText("OrderID"+ABName,OID);
        SayNotTooOften("There is an order to be checked",30);

        if (SubmitOrders)
        {
            for (dummy=0; dummy<40; dummy++)
                ibc.Sleep(50);  //Usually takes up to about a second for TWS to get acknowledgement from IB

             // Wait until order actually PreSubmitted - this will prevent submitting another order too quickly
             //     hopefully stops TWS/IB getting in a knot

             tradetime=GetPerformanceCounter()/1000;
             while ((GetPerformanceCounter()/1000 - tradetime) < 5) // give up after 5 seconds
             {
                 ibc.Reconnect();  //Refreshes ibc, and gets accurate status
                 ORderStatus = ibc.GetStatus( OID, True);
                 if (ORderStatus == "PreSubmitted" || ORderStatus == "Submitted" || ORderStatus == "Filled")
                     break;
             }
        }
    }

  else if( LastSell AND OrderID == "" )  
    {
        OID = ibc.PlaceOrder( IBName, "Sell", 1, "MKT", 0, TickSize,
                              "DAY", SubmitOrders, TickSize/0.0001, "outsideRTH" );


        for (dummy=0; dummy<40; dummy++)
            ibc.Sleep(50);  //Usually takes up to about a second for TWS to get acknowledgement from IB
        StaticVarSetText("OrderID"+ABName,OID);
        SayNotTooOften("There is an order to be checked",30);

        if (SubmitOrders)
        {
            for (dummy=0; dummy<40; dummy++)
                ibc.Sleep(50);  //Usually takes up to about a second for TWS to get acknowledgement from IB

             // Wait until order actually PreSubmitted - this will prevent submitting another order too quickly
             //     hopefully stops TWS/IB getting in a knot

             tradetime=GetPerformanceCounter()/1000;
             while ((GetPerformanceCounter()/1000 - tradetime) < 5) // give up after 5 seconds
             {
                 ibc.Reconnect();  //Refreshes ibc, and gets accurate status
                 ORderStatus = ibc.GetStatus( OID, True);
                 if (ORderStatus == "PreSubmitted" || ORderStatus == "Submitted" || ORderStatus == "Filled")
                     break;
             }
        }
    }

        // Only enter once the price moves in my desired direction, otherwise wait until next run of the exploration
        //     and check again, and again., ...
    else if( LastShort AND OrderID == "" AND (LastValue(C) >= (LastShortPrice)))  
    {
        OID = ibc.PlaceOrder( IBName, "Sell", IBOrderSize, "TRAIL", 0, TickSize,
                              "DAY", False, TickSize/0.0001, "outsideRTH" );
        // _TRACE("# Pos: 0, PrevOID: "+OrderID+", Sell 1, NewOID: "+OID);

        OIDLMT = ibc.PlaceOrder( IBName, "Buy", IBOrderSize, "LMT", LastShortPSLPrice, 0,
                                 "GTC", False, TickSize/0.0001, "outsideRTH", OID);
        OIDSTP = ibc.PlaceOrder( IBName, "Buy", IBOrderSize, "STP", 0, LastShortISLPrice,
                                 "GTC", SubmitOrders, TickSize/0.0001, "outsideRTH", OID);
        for (dummy=0; dummy<40; dummy++)
            ibc.Sleep(50);  //Usually takes up to about a second for TWS to get acknowledgement from IB
        StaticVarSetText("OrderID"+ABName,OID);
        StaticVarSetText("OrderIDLMT"+ABName,OIDLMT);
        StaticVarSetText("OrderIDSTP"+ABName,OIDSTP);
        SayNotTooOften("There is an order to be checked",30);

        if (SubmitOrders)
        {
            //Usually takes about a second for TWS to get acknowledgement from IB, so delay for 2 secs for safety
            for (dummy=0; dummy<40; dummy++)
                ibc.Sleep(50);  

             // Wait until order actually PreSubmitted - this will prevent submitting another order too quickly
             //     hopefully stops TWS/IB getting in a knot

            tradetime=GetPerformanceCounter()/1000;
            while ((GetPerformanceCounter()/1000 - tradetime) < 5) // give up after 5 seconds
            {
                ibc.Reconnect();  //Refreshes ibc, and gets accurate status
                ORderStatus = ibc.GetStatus( OID, True);
                if (ORderStatus == "PreSubmitted" || ORderStatus == "Submitted" || ORderStatus == "Filled")
                    break;
            }
        }
    }

    // Note LastOrderID will remain "" while waiting for price improvement so we may skip entering for the whole of the bar
    LastOrderID = StaticVarGetText("OrderID"+ABName);
    LastOrderIDLMT = StaticVarGetText("OrderIDLMT"+ABName);
    LastOrderIDSTP = StaticVarGetText("OrderIDSTP"+ABName);

    ORderStatus = ibc.GetStatus( LastOrderID , True );
    if( ORderStatus != "" ) StaticVarSetText("OrderStatus"+ABName,ORderStatus);

    ORderLMTStatus = ibc.GetStatus( LastOrderIDLMT , True );
    if( ORderLMTStatus != "" ) StaticVarSetText("OrderLMTStatus"+ABName,ORderLMTStatus);

    ORderSTPStatus = ibc.GetStatus( LastOrderIDSTP , True );
    if( ORderSTPStatus != "" ) StaticVarSetText("OrderStatusSTP"+ABName,ORderSTPStatus);
}
else IBPosSize = 0;

LastOrderID = StaticVarGetText("OrderID"+ABName);
ORderStatus = StaticVarGetText("OrderStatus"+ABName);
LastOrderIDLMT = StaticVarGetText("OrderIDLMT"+ABName);
ORderLMTStatus = StaticVarGetText("OrderLMTStatus"+ABName);
LastOrderIDSTP = StaticVarGetText("OrderIDSTP"+ABName);
ORderSTPStatus = StaticVarGetText("OrderSTPStatus"+ABName);
發表於 14-6-16 08:37 | 顯示全部樓層
kilroy 發表於 14-6-15 23:15
Hi,

可以丟 open 價的 limit 單

OK~
了解了!
感謝您熱心的回答
謝謝~
發表於 14-6-17 14:26 | 顯示全部樓層
本帖最後由 skyler 於 14-6-17 14:27 編輯

k大
請問一下您這段話
這是您用 AutoIt 自己做的嗎?!

2014-06-17_135730.png

--------------------------
另外自己遇到
同樣的資料
例如您提供的 6A #F
分別匯入至AB 與 MC 中
但AB與MC所計算出的指標數值不同
而影響策略的進出場

又以群益MC去查群益所提供的 AD1 澳幣連續月報價
結果資料上又與 6A #F 有所差異
使得指標計算出的結果不同
而影響進出場

結果就是
AB 吃 6A #F 資料 回策績效  成功
MC 吃 6A #F 資料 回策績效 失敗
群益MC 吃群益AD1資料 回策績效 失敗

而自己的策略在AB上
以您之前在另一篇文所提供的資料

加上在這串討論文中跟您索取的4種商品
共16種商品
結果都是呈現正向的結果

搞的自己心煩意亂
想詢問一下您的見解




 樓主| 發表於 14-6-17 14:35 | 顯示全部樓層
greg 發表於 14-6-16 00:10
謝謝K 大, 過去兩個星期 我已經不斷嘗試了無數次, K大的語法都用上, 但都無法做到我希望的結果
請大大再 ...

Hi,

我有空會寫一個範例,可以自設停損(包含IB TWS 送單)



評分

參與人數 1金錢 +2 收起 理由
skyler + 2 按一個讚

查看全部評分

 樓主| 發表於 14-6-17 14:45 | 顯示全部樓層
skyler 發表於 14-6-17 14:26
k大
請問一下您這段話
這是您用 AutoIt 自己做的嗎?!

Hi,

圖示裡,是 AB 作者提供的 IB Controller 對應 IB TWS

可以取得 IB TWS 的一些資訊,如 帳戶權益、目前持單部位、送單結果等

請參閱 http://www.amibroker.com/at/

或許國內券商 API 也有提供函數可以取得資訊,但那要自己寫程式

AB 作者提供這個下單介面(還開放原始碼),真的是解決一個大關卡

---
群益提供的歷史資料我有測過

但不知道他是電子盤還是人工、還是人工+電子

所以還是比較建議你直接使用 eSignal 的資料即可

會比較有差別的地方是換月 (rollover)

我是將 eSignal 報價直接與 IB 報價比對的,請安心使用

參考看看了
發表於 14-6-17 15:05 | 顯示全部樓層
本帖最後由 skyler 於 14-6-17 15:12 編輯
kilroy 發表於 14-6-17 14:45
Hi,

圖示裡,是 AB 作者提供的 IB Controller 對應 IB TWS


謝謝 k大您的回覆與幫忙
目前已經打算走
eSignal + AB + IB 的路了

雖然沒有那麼多資金能操盤
因此打算先匯10000 USD 開了IB戶頭後
再出金部份回來

算了一下
以券商的MC 每個月最少要1000
再加上 一口來回的手續費 6.5 X2 = 13 USD
比起 IB來回約為 5 USD 中間差了 8USD
一個月來回平均 50口 中間差的錢足夠接eSignal還有找了


為什麼您沒有單純想說
直接接IB的報價
而又要另外申請eSignal 呢?

-----------------------------
另外您上線前有用IB模擬帳戶測試過嗎?!


 樓主| 發表於 14-6-17 15:18 | 顯示全部樓層
本帖最後由 kilroy 於 14-6-17 15:25 編輯
skyler 發表於 14-6-17 15:05
謝謝 k大您的回覆與幫忙
目前已經打算走
eSignal + AB + IB 的路了

Hi,

申請 eSignal 可以到這個網站

http://chinafinpipe.com/

會比美國 eSignal 便宜一些,且可以接台灣期貨報價

申請很簡單,加會員開通就可以了

每個月自動從信用卡扣款,或是一次買一年

下 CME Group 的商品,只需訂閱
1. eSignal Premier
2. Extended Intraday History
3. CME Group Fee-Waived Globex Data

這樣一個月是 $155 / 上面那個網站可以到 $138

---
IB TWS 本身的報價 (market data) 我覺得不夠穩,有時還會斷線(但不影響 placing order)

為求報價穩定,就訂閱 eSignal 了

---
IB 的 paper account 非常讚

幾乎與真實帳戶一樣,也是測試你 AB 下單到 IB TWS 非常好的平台

在 paper account 測試好自動下單,無誤就可以安心下到 real account 了


參考看看

評分

參與人數 1金錢 +2 收起 理由
skyler + 2 好文章,我推薦

查看全部評分

發表於 14-6-17 16:06 | 顯示全部樓層
kilroy 發表於 14-6-17 15:18
Hi,

申請 eSignal 可以到這個網站

k大請問一下
我沒記錯的話 YM ZC ZS ZW 這四種
是在CBOT吧
那我要加訂那一項?


感謝~



您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

手機版|Archiver|站長信箱|廣告洽詢|COCO研究院

GMT+8, 24-11-22 22:44

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回復 返回頂部 返回列表
理財討論網站 |