COCO研究院

 找回密碼
 註冊
搜索
查看: 3010|回復: 6

[範例程式碼] 將文字檔內的交易價位標於K線圖上

[複製鏈接]
發表於 12-10-29 12:12 | 顯示全部樓層 |閱讀模式
本帖最後由 zaqimon 於 12-10-29 12:15 編輯

不知道有沒有人分享過
不過我也懶得找了所以自己寫一個
這三個AFL能把文字檔內紀錄的交易價位標示於K線圖上
並計算出損益Equity
也許可以當作回顧歷史交易的用途吧
有需要請自行修改

文字檔放置路徑(TRADE_FILE_PATH)請自行設定
文字檔預設檔名為symbol_name.txt
文字檔內容如下
###  Date Time, Current Position, Price ###
2012-09-25,-2,7771
2012-09-27,0,7700
2012-09-27,2,7700
2012-10-01,0,7689
2012-10-01,-2,7689
2012-10-02,0,7716
2012-10-02,2,7716
2012-10-04,-2,7700
2012-10-05,2,7715


擷取.PNG

  • izqStack.afl (請放到Include資料夾內)

  1. /*

  2. [20121016] zaqimon
  3. Simple Stack implementation using VarGet/VarSet.
  4. Store only number/array values.
  5. Stack values are volatile over each PASS of AFL execution.
  6. You will need StaticVar to persist Stack values.

  7. */

  8. STACK_NAME = "DefaultStackName";


  9. function SCountN(sname)
  10. {
  11.     out = VarGet(sname+"Count");
  12.     if(IsNull(out))
  13.         out = 0;
  14.     return out;
  15. }

  16. function SPushN(sname,in)
  17. {
  18.     top = SCountN(sname);
  19.     VarSet(sname+top, in);
  20.     VarSet(sname+"Count", top+1);
  21. }

  22. function SPopN(sname)
  23. {
  24.     out = Null;
  25.     top = SCountN(sname);
  26.     if(top > 0)
  27.     {
  28.         top -= 1;
  29.         VarSet(sname+"Count", top);
  30.         out = VarGet(sname+top);
  31.     }
  32.     return out;
  33. }

  34. function SCount()
  35. {
  36.     return SCountN(STACK_NAME);
  37. }

  38. function SPush(in)
  39. {
  40.     SPushN(STACK_NAME,in);
  41. }

  42. function SPop()
  43. {
  44.     return SPopN(STACK_NAME);
  45. }
複製代碼

  • ShowTrade.afl (請拖拉到主要K線圖上)

  1. /*

  2. [20121026] zaqimon
  3. The trade file name is like SymbolName.txt
  4. Place the trade file in TRADE_FILE_PATH directory
  5. The trade file looks like this:
  6. ###  Date Time, Current Position, Price ###
  7. 2012-09-25,-2,7771
  8. 2012-09-27,0,7700
  9. 2012-09-27,2,7700
  10. 2012-10-01,0,7689
  11. 2012-10-01,-2,7689
  12. 2012-10-02,0,7716
  13. 2012-10-02,2,7716
  14. 2012-10-04,-2,7700
  15. 2012-10-05,2,7715
  16. ...

  17. [20121018] zaqimon
  18. * copy from BSShow.afl


  19. */

  20. // initial options
  21. EnableTextOutput(False); // disable output to commentary window
  22. SetBarsRequired(sbrAll,sbrAll); // we need to see ALL bars
  23. SetOption("FuturesMode",True); // need set FuturesMode True or PointValue will be 1 for good

  24. // include
  25. #include_once <izqStack.afl> // stack operations: SPush/SPop/SCount

  26. // param
  27. OverrideTradeFile = ParamStr("Override trade file",""); // empty string means using default Trade Signal Filename
  28. ForceReload = ParamTrigger("Force reload", "!! CLICK to force reload !!");  // a force reload button

  29. // Change these values first if needed
  30. TRADE_FILE_PATH = "D:\\Futures\\Study\\ShowTrade\"; // Trade Signal Filename, Name()+".txt"
  31. TRADE_INTERVAL = inDaily; // match with Interval(2)
  32. MAX_OPEN_POSITION = 999; // avoid unreasonable values
  33. MAX_PPP = 5; // max pyramiding per day, 5 times per day should be far enough for trend trading
  34. EQUITY_SYMBOL = "~zqTradeEquity"; // symbol name of calculated equity

  35. // properties for PlotTradeSingle()
  36. VarSet("COLOR_B", colorRed);
  37. VarSet("COLOR_S", colorGreen);
  38. VarSet("COLOR_T", colorBrightGreen);
  39. VarSet("COLOR_R", colorDarkRed);
  40. VarSet("ARROW_B", shapeUpArrow);
  41. VarSet("ARROW_S", shapeHollowDownArrow);
  42. VarSet("ARROW_T", shapeDownArrow);
  43. VarSet("ARROW_R", shapeHollowUpArrow);

  44. // default value for ~zqTradeEquity
  45. gPLEquity = 0;
  46. gPLPoint = 0;

  47. function PushPrice(prevPos, nowPos, Price)
  48. {
  49.     for(i = abs(prevPos); i<abs(nowPos); i++) // should, abs(nowPos) > abs(prevPos)
  50.     {
  51.         SPush(Price*sign(nowPos)); // Push negative price on Short positions
  52.     }
  53. }

  54. function PopPrice(prevPos, nowPos)
  55. {
  56.     out = 0;
  57.     numLot = abs(prevPos) - abs(nowPos); // should, abs(nowPos) < abs(prevPos)
  58.     for(i=0; i<numLot; i++)
  59.     {
  60.         out += SPop();
  61.     }
  62.     out /= numLot; // average entry price
  63.     return out;
  64. }

  65. function SaveTradePrice(tradeType, Price, bi/*bar index*/)
  66. {
  67.     if(tradeType != "")
  68.     {
  69.         for(i=0;i<MAX_PPP;i++)
  70.         {
  71.             tp = StaticVarGet("TradePrice"+tradeType+i);
  72.             if(typeof(tp)!="array" || IsNull(tp[bi])) // if available, aka. not used, save trade price
  73.             {
  74.                 tp[bi] = Price;
  75.                 StaticVarSet("TradePrice"+tradeType+i,tp);
  76. //_TRACE("SaveTradePrice: "+"TradePrice"+tradeType+i+"["+bi+"] = "+tp[bi]);
  77.                 break;
  78.             }
  79.         }
  80.     }
  81.     else
  82.     {
  83.         _TRACE("error, tradeType is empty");
  84.     }
  85. }

  86. /*
  87. entry, exit prices are negative on Short trades for easy calculation
  88. lot is always positive for unambiguous
  89. */
  90. function UpdateTradeEquity(entry, exit, lot/*how many lots offset*/, bi/*bar index*/)
  91. {
  92.     global gPLEquity, gPLPoint; // gPLEquity - equity P/L, gPLPoint - point P/L
  93.     // P/L of this trade(offset)
  94.     pt = exit*lot - entry*lot; // pt = (exit - entry) * lot // writing like this may incur rounding error. why? 12000 --> 11999.999
  95.     eq = pt * PointValue;
  96.     // cumulated P/L, typeof() is still 'number'
  97.     pt += gPLPoint[bi];
  98.     eq += gPLEquity[bi];
  99.     // fill into global array with a little trick
  100.     // we offset - pt, eq - into array and fill them from [bi] to [BarCount-1]
  101.     gPLPoint =  IIf(IsNull(Ref(pt, -bi)), gPLPoint,  Ref(pt,-bi));
  102.     gPLEquity = IIf(IsNull(Ref(eq, -bi)), gPLEquity, Ref(eq,-bi));
  103. }

  104. /*
  105. save Trade Equiy to symbol - EQUITY_SYMBOL(~zqTradeEquity)
  106. */
  107. function SaveTradeEquity()
  108. {
  109.     global gPLEquity, gPLPoint; // X = gPLEquity, Vol = gPLPoint
  110.    
  111.     if(typeof(gPLEquity)=="array" && typeof(gPLPoint)=="array")
  112.     {
  113.         AddToComposite(gPLEquity, EQUITY_SYMBOL, "X", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
  114.         AddToComposite(gPLPoint,  EQUITY_SYMBOL, "V", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
  115.     }
  116.     else
  117.     {
  118.         AddToComposite(0, EQUITY_SYMBOL, "X", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
  119.         AddToComposite(0, EQUITY_SYMBOL, "V", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
  120.     }
  121. }

  122. /*
  123. on error, return <0; else, return lines processed correctly
  124. read file to StaticVar
  125. update ~zqTradeEquity
  126. */
  127. function ReadTradeFile(tfname)
  128. {
  129.     out = 0;
  130. _TRACE("ReadTradeFile: "+tfname);
  131.     fh = fopen(tfname, "r");
  132.     if(fh)
  133.     {
  134.         arDT = DateTime();
  135.         cntDT = 0; // 1 pass index counter from 0 to BarCount-1
  136.         prevPos = 0; // previous position
  137.         avgEntryPrice = 0; // average entry price, also used as a trigger for equity calculation
  138.         tradeType = ""; // "B","S","T","R" for Buy, Sell, shorT, coveR
  139.         
  140.         while(!feof(fh))
  141.         {
  142.             tpLine = fgets( fh );
  143.             tpItem = 1 + StrCount(tpLine,",");
  144.             if(tpItem != 3) // sanity check, 3 items expected
  145.             {
  146.                 // don't care empty lines. bug?!
  147.                 // bug?! after the 2nd lines of multiple empty line, fgets return \n
  148.                 if(tpLine!="" && tpLine!="\n") _TRACE("error[ShowTrade]: tpItem count != 3 -- "+tpLine);
  149.                 continue;
  150.             }
  151.             tpDate = StrToDateTime(StrExtract(tpLine, 0)); // DateTime
  152.             tpPos = StrToNum(StrExtract(tpLine, 1)); // current open positions, NaN will all be converted to 0
  153.             tpPrice = StrToNum(StrExtract(tpLine, 2)); // trade price
  154.             if(abs(tpPos) > MAX_OPEN_POSITION) // limit tpPos -999 ~ 999
  155.             {
  156.                 _TRACE("error[ShowTrade]: tpPos exceed MAX_OPEN_POSITION -- "+tpLine);
  157.                 continue;
  158.             }
  159.             if(tpPrice<=0) // real trade price should always be positive
  160.             {
  161.                 _TRACE("error[ShowTrade]: tpPrice should be positive !? -- "+tpLine);
  162.                 continue;
  163.             }
  164.             
  165.             if(prevPos != tpPos) // positions changed
  166.             {
  167.                 // cross 0, offset all positions before open new positions
  168.                 if(prevPos*tpPos < 0) // offset + open, crossing 0
  169.                 {
  170.                     avgEntryPrice = PopPrice(prevPos, 0); // average entry price
  171.                     offsetLot = abs(prevPos);
  172.                     PushPrice(0, tpPos, tpPrice);
  173.                     if(tpPos>0) // newly opened positions precede offset's, just ignore offset tradeType
  174.                         tradeType = "B";
  175.                     else
  176.                         tradeType = "T";
  177.                 }
  178.                 else if(abs(tpPos)-abs(prevPos) < 0) // offset
  179.                 {
  180.                     avgEntryPrice = PopPrice(prevPos, tpPos); // average entry price
  181.                     offsetLot = abs(prevPos) - abs(tpPos);
  182.                     if(prevPos>0)
  183.                         tradeType = "S";
  184.                     else
  185.                         tradeType = "R";
  186.                 }
  187.                 else // open
  188.                 {
  189.                     PushPrice(prevPos, tpPos, tpPrice);
  190.                     if(tpPos>0)
  191.                         tradeType = "B";
  192.                     else
  193.                         tradeType = "T";
  194.                 }
  195.                
  196.                 // search bi (bar index) and save the trade price into StaticVar
  197.                 while(DateTimeDiff(arDT[cntDT], tpDate) < 0) // compare DateTime with DateTimeDiff(), NOT '<'
  198.                 {
  199.                     if(cntDT >= BarCount-1) break; // bound check. from 0 ~ BarCount-1.
  200.                     cntDT++;
  201.                 }
  202.                 if(arDT[cntDT] == tpDate) // date matched, save the trade price (positive price)
  203.                 {
  204.                     SaveTradePrice(tradeType, tpPrice, cntDT); // for overlaying onto the price chart
  205.                     // update ~zqTradeEquity, if there are offset trades, avgEntryPrice != 0 as a trigger
  206.                     if(avgEntryPrice != 0)
  207.                     {
  208.                         UpdateTradeEquity(avgEntryPrice, tpPrice*sign(prevPos), offsetLot, cntDT); // price may be negative for easy calculation
  209.                     }
  210.                 }
  211.                 avgEntryPrice = 0;
  212.                 prevPos = tpPos;
  213.                 ++out; // how many lines processed
  214.             } // END if(prevPos != tpPos)
  215.         } // END while(!feof(fh))
  216.         SaveTradeEquity(); // save to symbol - "~zqTradeEquity"
  217.         fclose(fh);
  218.     }
  219.     else
  220.     {
  221.         // fopen fail
  222.         out = -1;
  223.     }
  224.     return out;
  225. }

  226. function PlotTradeSingle(type /* should be "B","S","T","R" */)
  227. {
  228.     for(i=0; i < MAX_PPP; i++)
  229.     {
  230.         arr_tp = StaticVarGet("TradePrice"+type+i);
  231.         if(typeof(arr_tp) != "array")
  232.             break;
  233.         if(i == 0)
  234.         {
  235.             arrow_type = IIf(IsNull(arr_tp), shapeNone, VarGet("ARROW_"+type));
  236.             arrow_color = IIf(type=="B" || type=="R", colorRed, colorBrightGreen); // VarGet("COLOR_"+type); // it looks weird if hollow arrows are darkened
  237.             anchor_point = IIf(type=="B" || type=="R", L, H);
  238.             // use default offset(-12), overlay solid and hollow arrows for cleanliness
  239.             PlotShapes( arrow_type, arrow_color, 0 /*this is not Z-order*/ , anchor_point );
  240.         }
  241.         
  242.         Plot(arr_tp, type+i, VarGet("COLOR_"+type),
  243.             styleDots | styleNoLine | styleNoTitle | styleNoLabel, 0, 0, 0, 10 /*Z-order*/ );
  244.     }
  245. }

  246. function PlotTrades()
  247. {
  248. //    _TRACE("in PlotTrades");
  249.     // Plot first show front. I'd like bright color at front.
  250.     PlotTradeSingle("B"); // Buy - colorRed
  251.     PlotTradeSingle("T"); // shorT - colorBrightGreen
  252.     PlotTradeSingle("S"); // Sell
  253.     PlotTradeSingle("R"); // coveR
  254. }

  255. function ShowTrade_Main()
  256. {
  257.     if(ForceReload)
  258.     {
  259.         _TRACE("!! Force Reloading !!");
  260.         StaticVarRemove("STPrevSymbol");
  261.     }
  262.     // normal symbol && symbol changed && correct interval ==> ReadTradeFile()
  263.     if(StrLeft(Name(),1) != "~" &&
  264.     ( /* reload file when 1.change of OverrideTradeFile (if not empty) OR 2. change of Name() */
  265.         (OverrideTradeFile != "" && OverrideTradeFile != StaticVarGetText("STPrevSymbol"))
  266.         ||
  267.         (OverrideTradeFile == "" && Name() != StaticVarGetText("STPrevSymbol"))
  268.     )
  269.     && Interval(0) == TRADE_INTERVAL)
  270.     {
  271.         // StaticVarRemove("*") here will re-read on each symbol change no matter ReadTradeFile successful or not
  272.         StaticVarRemove("*"); // clear all StaticVar
  273.         
  274.         if(OverrideTradeFile != "")
  275.         {
  276.             StaticVarSetText("STPrevSymbol", OverrideTradeFile);
  277.             TradeFile = TRADE_FILE_PATH + OverrideTradeFile;
  278.         }
  279.         else
  280.         {
  281.             StaticVarSetText("STPrevSymbol", Name());
  282.             TradeFile = TRADE_FILE_PATH + Name() + ".txt";
  283.         }
  284.         re = ReadTradeFile(TradeFile);
  285.         if(re >= 0)
  286.         {
  287.             StaticVarSetText("STLoadedSymbol", Name());
  288.             // ~zqTradeEquity just get updated
  289.             // we need little trick to make AmiBroker refresh again in order to show ~zqTradeEquity in ShowTradeEquity.afl
  290.             AB = CreateObject("Broker.Application");
  291.             AB.RefreshAll();
  292.         }
  293.     }
  294.    
  295.     // loaded symbol matched && correct interval ==> PlotTrades()
  296.     if(Name() == StaticVarGetText("STLoadedSymbol") && Interval(0) == TRADE_INTERVAL)
  297.     {
  298.         PlotTrades();
  299.     }
  300. }

  301. ShowTrade_Main();

  302. //_TRACE(""+Name()+" : "+StaticVarGetText("STPrevSymbol")+" : "+StaticVarGetText("STLoadedSymbol"));

複製代碼

  • ShowTradeEquity.afl (顯示Equity用)

  1. Ticker = ParamStr("Symbol", "~zqTradeEquity");
  2. PlotForeign( Ticker, Ticker, ParamColor("Color", colorCycle ), ParamStyle("Style", styleArea, maskAll));
複製代碼


評分

參與人數 2金錢 +7 收起 理由
enochyu + 2 按一個讚!
kilroy + 5 按一個讚!

查看全部評分

發表於 12-10-29 13:29 | 顯示全部樓層
板大認真唷~~~

         
回復 支持 1 反對 0

使用道具 舉報

發表於 12-10-30 06:38 | 顯示全部樓層
@zaqimon,, thanks for sharing

Have you tried

SetOption( "RefreshWhenCompleted" );

instead of

AB = CreateObject( "Broker.Application" );
AB.RefreshAll();

發表於 12-10-30 06:44 | 顯示全部樓層
@zaqimon,

Does intraday datetime work also?

like

###  Date Time, Current Position, Price ###
2012-09-25 07:01,-2,7771
2012-09-27 09:45,0,7700
2012-09-27 13:23,2,7700
2012-10-01 08:56,0,7689
2012-10-01 16:43,-2,7689

Is -2 -> short
2 -> buy?
0 -> ?
發表於 12-10-30 09:00 | 顯示全部樓層
多謝版主分享
 樓主| 發表於 12-10-30 09:30 | 顯示全部樓層
joshsmi 發表於 12-10-30 06:44
@zaqimon,

Does intraday datetime work also?

我猜intraday應該也可以用吧
然後TRADE_INTERVAL改成例如in1Minute之類的
不過我沒測試過

0就是手上沒有倉位(純平倉用)
2就是多單部位持倉兩口
-4就是空單部位持倉四口
文字檔紀錄可以直接多空對翻不需要紀錄平倉
程式會自動先平倉計算損益然後再開新倉
例如可以這樣寫表示
先進空單三口
再進多單八口(內含平倉的三口)也就是變成多單持倉五口
2012-09-25,-3,7771
2012-09-27,5,7700


發表於 12-10-31 08:35 | 顯示全部樓層
感謝版大無私的分享

先收下 好好研究一番
您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

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

GMT+8, 24-11-23 09:14

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

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