Show trade prices on the chart and also calculate equity change.
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
- izqStack.afl (put it in the Include folder, simple implementation of Stack)
/* [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 (drag-drop onto the price chart)
/* [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 - nto 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 (insert new chart for displaying the calculated equity)
Ticker = ParamStr("Symbol", "~zqTradeEquity"); PlotForeign( Ticker, Ticker, ParamColor("Color", colorCycle ), ParamStyle("Style", styleArea, maskAll));
沒有留言:
張貼留言