|
本帖最後由 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
- izqStack.afl (請放到Include資料夾內)
- /*
- [20121016] zaqimon
- Simple Stack implementation using VarGet/VarSet.
- Store only number/array values.
- Stack values are volatile over each PASS of AFL execution.
- You will need StaticVar to persist Stack values.
- */
- STACK_NAME = "DefaultStackName";
- function SCountN(sname)
- {
- out = VarGet(sname+"Count");
- if(IsNull(out))
- out = 0;
- return out;
- }
- function SPushN(sname,in)
- {
- top = SCountN(sname);
- VarSet(sname+top, in);
- VarSet(sname+"Count", top+1);
- }
- function SPopN(sname)
- {
- out = Null;
- top = SCountN(sname);
- if(top > 0)
- {
- top -= 1;
- VarSet(sname+"Count", top);
- out = VarGet(sname+top);
- }
- return out;
- }
- function SCount()
- {
- return SCountN(STACK_NAME);
- }
- function SPush(in)
- {
- SPushN(STACK_NAME,in);
- }
- function SPop()
- {
- return SPopN(STACK_NAME);
- }
複製代碼
- ShowTrade.afl (請拖拉到主要K線圖上)
- /*
- [20121026] zaqimon
- The trade file name is like SymbolName.txt
- Place the trade file in TRADE_FILE_PATH directory
- The trade file looks like this:
- ### 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
- ...
- [20121018] zaqimon
- * copy from BSShow.afl
- */
- // initial options
- EnableTextOutput(False); // disable output to commentary window
- SetBarsRequired(sbrAll,sbrAll); // we need to see ALL bars
- SetOption("FuturesMode",True); // need set FuturesMode True or PointValue will be 1 for good
- // include
- #include_once <izqStack.afl> // stack operations: SPush/SPop/SCount
- // param
- OverrideTradeFile = ParamStr("Override trade file",""); // empty string means using default Trade Signal Filename
- ForceReload = ParamTrigger("Force reload", "!! CLICK to force reload !!"); // a force reload button
- // Change these values first if needed
- TRADE_FILE_PATH = "D:\\Futures\\Study\\ShowTrade\"; // Trade Signal Filename, Name()+".txt"
- TRADE_INTERVAL = inDaily; // match with Interval(2)
- MAX_OPEN_POSITION = 999; // avoid unreasonable values
- MAX_PPP = 5; // max pyramiding per day, 5 times per day should be far enough for trend trading
- EQUITY_SYMBOL = "~zqTradeEquity"; // symbol name of calculated equity
- // properties for PlotTradeSingle()
- VarSet("COLOR_B", colorRed);
- VarSet("COLOR_S", colorGreen);
- VarSet("COLOR_T", colorBrightGreen);
- VarSet("COLOR_R", colorDarkRed);
- VarSet("ARROW_B", shapeUpArrow);
- VarSet("ARROW_S", shapeHollowDownArrow);
- VarSet("ARROW_T", shapeDownArrow);
- VarSet("ARROW_R", shapeHollowUpArrow);
- // default value for ~zqTradeEquity
- gPLEquity = 0;
- gPLPoint = 0;
- function PushPrice(prevPos, nowPos, Price)
- {
- for(i = abs(prevPos); i<abs(nowPos); i++) // should, abs(nowPos) > abs(prevPos)
- {
- SPush(Price*sign(nowPos)); // Push negative price on Short positions
- }
- }
- function PopPrice(prevPos, nowPos)
- {
- out = 0;
- numLot = abs(prevPos) - abs(nowPos); // should, abs(nowPos) < abs(prevPos)
- for(i=0; i<numLot; i++)
- {
- out += SPop();
- }
- out /= numLot; // average entry price
- return out;
- }
- function SaveTradePrice(tradeType, Price, bi/*bar index*/)
- {
- if(tradeType != "")
- {
- for(i=0;i<MAX_PPP;i++)
- {
- tp = StaticVarGet("TradePrice"+tradeType+i);
- if(typeof(tp)!="array" || IsNull(tp[bi])) // if available, aka. not used, save trade price
- {
- tp[bi] = Price;
- StaticVarSet("TradePrice"+tradeType+i,tp);
- //_TRACE("SaveTradePrice: "+"TradePrice"+tradeType+i+"["+bi+"] = "+tp[bi]);
- break;
- }
- }
- }
- else
- {
- _TRACE("error, tradeType is empty");
- }
- }
- /*
- entry, exit prices are negative on Short trades for easy calculation
- lot is always positive for unambiguous
- */
- function UpdateTradeEquity(entry, exit, lot/*how many lots offset*/, bi/*bar index*/)
- {
- global gPLEquity, gPLPoint; // gPLEquity - equity P/L, gPLPoint - point P/L
- // P/L of this trade(offset)
- pt = exit*lot - entry*lot; // pt = (exit - entry) * lot // writing like this may incur rounding error. why? 12000 --> 11999.999
- eq = pt * PointValue;
- // cumulated P/L, typeof() is still 'number'
- pt += gPLPoint[bi];
- eq += gPLEquity[bi];
- // fill into global array with a little trick
- // we offset - pt, eq - into array and fill them from [bi] to [BarCount-1]
- gPLPoint = IIf(IsNull(Ref(pt, -bi)), gPLPoint, Ref(pt,-bi));
- gPLEquity = IIf(IsNull(Ref(eq, -bi)), gPLEquity, Ref(eq,-bi));
- }
- /*
- save Trade Equiy to symbol - EQUITY_SYMBOL(~zqTradeEquity)
- */
- function SaveTradeEquity()
- {
- global gPLEquity, gPLPoint; // X = gPLEquity, Vol = gPLPoint
-
- if(typeof(gPLEquity)=="array" && typeof(gPLPoint)=="array")
- {
- AddToComposite(gPLEquity, EQUITY_SYMBOL, "X", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
- AddToComposite(gPLPoint, EQUITY_SYMBOL, "V", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
- }
- else
- {
- AddToComposite(0, EQUITY_SYMBOL, "X", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
- AddToComposite(0, EQUITY_SYMBOL, "V", atcFlagDeleteValues|atcFlagCompositeGroup|atcFlagEnableInIndicator);
- }
- }
- /*
- on error, return <0; else, return lines processed correctly
- read file to StaticVar
- update ~zqTradeEquity
- */
- function ReadTradeFile(tfname)
- {
- out = 0;
- _TRACE("ReadTradeFile: "+tfname);
- fh = fopen(tfname, "r");
- if(fh)
- {
- arDT = DateTime();
- cntDT = 0; // 1 pass index counter from 0 to BarCount-1
- prevPos = 0; // previous position
- avgEntryPrice = 0; // average entry price, also used as a trigger for equity calculation
- tradeType = ""; // "B","S","T","R" for Buy, Sell, shorT, coveR
-
- while(!feof(fh))
- {
- tpLine = fgets( fh );
- tpItem = 1 + StrCount(tpLine,",");
- if(tpItem != 3) // sanity check, 3 items expected
- {
- // don't care empty lines. bug?!
- // bug?! after the 2nd lines of multiple empty line, fgets return \n
- if(tpLine!="" && tpLine!="\n") _TRACE("error[ShowTrade]: tpItem count != 3 -- "+tpLine);
- continue;
- }
- tpDate = StrToDateTime(StrExtract(tpLine, 0)); // DateTime
- tpPos = StrToNum(StrExtract(tpLine, 1)); // current open positions, NaN will all be converted to 0
- tpPrice = StrToNum(StrExtract(tpLine, 2)); // trade price
- if(abs(tpPos) > MAX_OPEN_POSITION) // limit tpPos -999 ~ 999
- {
- _TRACE("error[ShowTrade]: tpPos exceed MAX_OPEN_POSITION -- "+tpLine);
- continue;
- }
- if(tpPrice<=0) // real trade price should always be positive
- {
- _TRACE("error[ShowTrade]: tpPrice should be positive !? -- "+tpLine);
- continue;
- }
-
- if(prevPos != tpPos) // positions changed
- {
- // cross 0, offset all positions before open new positions
- if(prevPos*tpPos < 0) // offset + open, crossing 0
- {
- avgEntryPrice = PopPrice(prevPos, 0); // average entry price
- offsetLot = abs(prevPos);
- PushPrice(0, tpPos, tpPrice);
- if(tpPos>0) // newly opened positions precede offset's, just ignore offset tradeType
- tradeType = "B";
- else
- tradeType = "T";
- }
- else if(abs(tpPos)-abs(prevPos) < 0) // offset
- {
- avgEntryPrice = PopPrice(prevPos, tpPos); // average entry price
- offsetLot = abs(prevPos) - abs(tpPos);
- if(prevPos>0)
- tradeType = "S";
- else
- tradeType = "R";
- }
- else // open
- {
- PushPrice(prevPos, tpPos, tpPrice);
- if(tpPos>0)
- tradeType = "B";
- else
- tradeType = "T";
- }
-
- // search bi (bar index) and save the trade price into StaticVar
- while(DateTimeDiff(arDT[cntDT], tpDate) < 0) // compare DateTime with DateTimeDiff(), NOT '<'
- {
- if(cntDT >= BarCount-1) break; // bound check. from 0 ~ BarCount-1.
- cntDT++;
- }
- if(arDT[cntDT] == tpDate) // date matched, save the trade price (positive price)
- {
- SaveTradePrice(tradeType, tpPrice, cntDT); // for overlaying onto the price chart
- // update ~zqTradeEquity, if there are offset trades, avgEntryPrice != 0 as a trigger
- if(avgEntryPrice != 0)
- {
- UpdateTradeEquity(avgEntryPrice, tpPrice*sign(prevPos), offsetLot, cntDT); // price may be negative for easy calculation
- }
- }
- avgEntryPrice = 0;
- prevPos = tpPos;
- ++out; // how many lines processed
- } // END if(prevPos != tpPos)
- } // END while(!feof(fh))
- SaveTradeEquity(); // save to symbol - "~zqTradeEquity"
- fclose(fh);
- }
- else
- {
- // fopen fail
- out = -1;
- }
- return out;
- }
- function PlotTradeSingle(type /* should be "B","S","T","R" */)
- {
- for(i=0; i < MAX_PPP; i++)
- {
- arr_tp = StaticVarGet("TradePrice"+type+i);
- if(typeof(arr_tp) != "array")
- break;
- if(i == 0)
- {
- arrow_type = IIf(IsNull(arr_tp), shapeNone, VarGet("ARROW_"+type));
- arrow_color = IIf(type=="B" || type=="R", colorRed, colorBrightGreen); // VarGet("COLOR_"+type); // it looks weird if hollow arrows are darkened
- anchor_point = IIf(type=="B" || type=="R", L, H);
- // use default offset(-12), overlay solid and hollow arrows for cleanliness
- PlotShapes( arrow_type, arrow_color, 0 /*this is not Z-order*/ , anchor_point );
- }
-
- Plot(arr_tp, type+i, VarGet("COLOR_"+type),
- styleDots | styleNoLine | styleNoTitle | styleNoLabel, 0, 0, 0, 10 /*Z-order*/ );
- }
- }
- function PlotTrades()
- {
- // _TRACE("in PlotTrades");
- // Plot first show front. I'd like bright color at front.
- PlotTradeSingle("B"); // Buy - colorRed
- PlotTradeSingle("T"); // shorT - colorBrightGreen
- PlotTradeSingle("S"); // Sell
- PlotTradeSingle("R"); // coveR
- }
- function ShowTrade_Main()
- {
- if(ForceReload)
- {
- _TRACE("!! Force Reloading !!");
- StaticVarRemove("STPrevSymbol");
- }
- // normal symbol && symbol changed && correct interval ==> ReadTradeFile()
- if(StrLeft(Name(),1) != "~" &&
- ( /* reload file when 1.change of OverrideTradeFile (if not empty) OR 2. change of Name() */
- (OverrideTradeFile != "" && OverrideTradeFile != StaticVarGetText("STPrevSymbol"))
- ||
- (OverrideTradeFile == "" && Name() != StaticVarGetText("STPrevSymbol"))
- )
- && Interval(0) == TRADE_INTERVAL)
- {
- // StaticVarRemove("*") here will re-read on each symbol change no matter ReadTradeFile successful or not
- StaticVarRemove("*"); // clear all StaticVar
-
- if(OverrideTradeFile != "")
- {
- StaticVarSetText("STPrevSymbol", OverrideTradeFile);
- TradeFile = TRADE_FILE_PATH + OverrideTradeFile;
- }
- else
- {
- StaticVarSetText("STPrevSymbol", Name());
- TradeFile = TRADE_FILE_PATH + Name() + ".txt";
- }
- re = ReadTradeFile(TradeFile);
- if(re >= 0)
- {
- StaticVarSetText("STLoadedSymbol", Name());
- // ~zqTradeEquity just get updated
- // we need little trick to make AmiBroker refresh again in order to show ~zqTradeEquity in ShowTradeEquity.afl
- AB = CreateObject("Broker.Application");
- AB.RefreshAll();
- }
- }
-
- // loaded symbol matched && correct interval ==> PlotTrades()
- if(Name() == StaticVarGetText("STLoadedSymbol") && Interval(0) == TRADE_INTERVAL)
- {
- PlotTrades();
- }
- }
- ShowTrade_Main();
- //_TRACE(""+Name()+" : "+StaticVarGetText("STPrevSymbol")+" : "+StaticVarGetText("STLoadedSymbol"));
複製代碼
- ShowTradeEquity.afl (顯示Equity用)
- Ticker = ParamStr("Symbol", "~zqTradeEquity");
- PlotForeign( Ticker, Ticker, ParamColor("Color", colorCycle ), ParamStyle("Style", styleArea, maskAll));
複製代碼
|
評分
-
查看全部評分
|