mjj38
- ago
I believe I found a small bug. It occurs when the symbol history is missing a bar for a given date.

For example:
For the symbol REGN on 6/9/15 (there is no bar data for that date).
When the trade loop runs for 6/9/15 it includes this new position even though it isn't filled until 6/10/15. This is slightly mis-stating the equity and cash for that day.

Settings Used


I created a sample strategy that demonstrates it.
CODE:
using WealthLab.Backtest; using System; using System.Linq; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) {          _rsi = RSI.Series(bars.Close, 14); } public override void Execute(BarHistory bars, int idx) {          if (!HasOpenPosition(bars, PositionType.Long)) {             Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.Limit, bars.Low[idx], 0, "");             t.Weight = _rsi[idx];          } else {             ClosePosition(LastPosition, OrderType.Limit, bars.High[idx], ""); } } public override void PostExecute(DateTime dt, List<BarHistory> participants) {          double startingCapital = Backtester.StartingCapital;          double marginFactor = Backtester.PositionSize.MarginFactor;          List<Position> allPositions = GetPositionsAllSymbols().Where(p=>p.NSF is false).ToList();          List<Position> newClosedPositions = allPositions.Where(p =>p.IsOpen is false && p.ExitDate.CompareTo(dt) >= 0).ToList();          List<Position> openPositions = allPositions.Where(p =>p.IsOpen).ToList();           /*          foreach (Position p in newClosedPositions)          {             int ix = p.Bars.DateTimes.IndexOf(dt);             if (ix <0)             {                WriteToDebugLog($"Step[{dt,10:d}] {p.Symbol,-17} ExitDate[{p.ExitDate,10:d}]", false);             }          } */          double closedNetProfit = allPositions.Where(p =>p.IsOpen is false).Sum(p =>p.Profit);          double openCostBasis = openPositions.Sum(p=>p.CostBasis);          double cash = startingCapital + closedNetProfit - openCostBasis;          double totalMtm = GetTotalMtm(openPositions, dt);          double equity = cash + totalMtm;          if (!IsAlmostEqual(CurrentCash, cash) || !IsAlmostEqual(CurrentEquity, equity))          {             WriteToDebugLog($"*************************************************{dt,10:d}********************************************************", false);             GetTotalMtm(openPositions, dt, true);             WriteToDebugLog(string.Empty, false);             WriteToDebugLog($"Starting Capital {startingCapital,12:N2}", false);             WriteToDebugLog($"Closed Net Profit +{closedNetProfit,12:N2}", false);             WriteToDebugLog($"Open Cost Basis -{openCostBasis,12:N2}", false);             WriteToDebugLog($"----------------------------------------------------------", false);             WriteToDebugLog($"Cash ={cash,12:N2} Difference {CurrentCash - cash,10:N2}", false);             WriteToDebugLog($"MTM +{totalMtm,12:N2}",false);             WriteToDebugLog($"----------------------------------------------------------", false);             WriteToDebugLog($"Equity ={equity,12:N2} Difference {CurrentEquity-equity,10:N2}", false);             WriteToDebugLog(String.Empty, false);          }       }       private double GetTotalMtm(List<Position> positions, DateTime dt, bool print = false)       {          bool header = true;          double tmtm = 0, runMtm = 0, runCost = 0;          foreach (Position p in positions)          {             double mtm =0,nextMtm = 0, closedMtm = 0;             DateTime prevDt=dt, nextDt = dt;             int ix = p.Bars.DateTimes.IndexOf(dt);                          //   Missing Bar for Date             if (ix < 0)             {                prevDt = p.Bars.DateTimes.Where(d =>d.CompareTo(dt) <0).LastOrDefault();                if (prevDt != DateTime.MinValue)                {                   mtm = p.ValueAsOf(p.Bars.DateTimes.IndexOf(prevDt), false);                }                nextDt = p.Bars.DateTimes.Where(d =>d.CompareTo(dt) >=0).FirstOrDefault();                if (nextDt != DateTime.MinValue)                {                   nextMtm = p.ValueAsOf(p.Bars.DateTimes.IndexOf(nextDt), false);                }                if (!p.IsOpen)                {                   closedMtm = (p.ExitPrice - p.EntryPrice) * p.Quantity;                }             }             //   Bar Exists             else             {                mtm = p.ValueAsOf(ix, false);             }             //   Print details             if (print)             {                string note = ix < 0 ? $"Missing Bar for {dt:d} [{p.ToString()}] ** Shouldn't be included **" : string.Empty;                runMtm += mtm;runCost +=p.CostBasis;                if(header)WriteToDebugLog($"{"Symbol".PadRight(23)}{"EntryDate",10}{"MTM",14}{"SumMTM",13}{"Cost",14}{"SumCost",13}", false);                header = false;                WriteToDebugLog($"{p.Symbol.PadRight(20)} [{p.EntryDate,10:d}] [{mtm,10:N2}][{runMtm,11:N2}] [{p.CostBasis,10:N2}][{runCost,11:N2}] {note}", false);             }             tmtm += mtm;          }          return tmtm;       }       private bool IsAlmostEqual(double v1, double v2)       {          return Math.Abs(v1 -v2) < 0.0000001;       }       private RSI _rsi; } }
0
327
Solved
7 Replies

Reply

Bookmark

Sort
mjj38
- ago
#1
Debug Log Output

0
Glitch8
 ( 9.00% )
- ago
#2
Thank you, yes it looks like a very obscure case but we should put some work into accounting for that situation.
1
mjj38
- ago
#3
Thanks Glitch. Was this added to the wishlist items?
0
Glitch8
 ( 9.00% )
- ago
#4
It's been added as a low priority item in our bug tracking system.
0
Glitch8
 ( 9.00% )
- ago
#5
BTW, my chart for REGN does have data for 6/9/2015 (WealthData) so maybe right click to refresh the REGN data to overcome this.
0
Best Answer
mjj38
- ago
#6
Thanks Glitch. I agree it's not a big issue (nor urgent) but it would be good to get it fixed eventually. Do you know if corporate events which cause trading to be halted for some reason could cause the missing data?

Also, I could see this happening if you combine stocks that trade in different markets as they could have different holidays.
0
Glitch8
 ( 9.00% )
- ago
#7
It sounds like those conditions could indeed cause this situation to occur.
0

Reply

Bookmark

Sort