Hi there! I'm trying to backtest a simple long TQQQ ATM call strategy. Buy 1 contract the day after OpEx, and sell the day of OpEx. Rinse and repeat.
I tried to implement in C# code using the webinar and Cone's blog. I think it's close, but I'm having trouble implementing historical IV using Schwab data provider. I know that you can use synthetic bars as well for the daily data, but I'd like to see historical as well.
I tried to implement in C# code using the webinar and Cone's blog. I think it's close, but I'm having trouble implementing historical IV using Schwab data provider. I know that you can use synthetic bars as well for the daily data, but I'd like to see historical as well.
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; using System.Windows.Media.Imaging; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { string _osym; DateTime _expiry; BarHistory _obars; // the option's BarHistory int _hash = -1; UniqueList<string> _syms = new UniqueList<string>(); TimeSeries _iv; // implied volatility estimate int useSchwab; //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { Position opt = FindOpenPositionAllSymbols(_hash); if (opt == null) { // Use a synthetic contract. Cone states in webinar that synthetic can work for daily bars. _osym = OptionSynthetic.GetOptionsSymbol(bars, OptionType.Call, bars.Close[idx], bars.DateTimes[idx], 30, useWeeklies: false, allowExpired: true); _hash = Math.Abs(_osym.GetHashCode()); _expiry = OptionsHelper.SymbolExpiry(_osym); WriteToDebugLog("-------"); WriteToDebugLog("Buying on " + bars.DateTimes[idx]); WriteToDebugLog("Should Expire on " + _expiry); //GetHistory generates Barhistory objects based on Stock's BarHistory and Implied IV _obars = OptionSynthetic.GetHistory(bars, _osym, 0.50); _syms.Add(_obars.Symbol); // Buy 1 Call. Transaction t2 = PlaceTrade(_obars, TransactionType.Buy, OrderType.Market, 0, _hash, "Buy 1 call"); t2.Quantity = 1; } else { // close the position at expiry if (bars.DateTimes[idx].AddDays(1) >= _expiry) { ClosePosition(opt, OrderType.Market, 0, "Expired"); WriteToDebugLog("Selling on " + bars.DateTimes[idx]); } } } public override void Cleanup(BarHistory bars) { // don't overload the chart with panes - plot only the last 5 contracts that were traded in Single Symbol Mode if (!Backtester.Strategy.SingleSymbolMode) return; // Indicate the trades foreach (Position p in GetPositionsAllSymbols()) { if (p.Bars == bars || _syms.IndexOf(p.Symbol) < _syms.Count - 5) continue; PlotBarHistory(p.Bars, p.Symbol); if (!p.NSF) { if (p.EntryBar > 0) DrawTextVAlign("▲", p.EntryBar, p.Bars.Low[p.EntryBar] * 0.95, VerticalAlignment.Top, WLColor.NeonBlue, 16, 0, 0, p.Symbol, true); if (p.ExitBar > 0) DrawTextVAlign("▼", p.ExitBar, p.Bars.High[p.ExitBar] * 1.05, VerticalAlignment.Bottom, WLColor.NeonFuschia, 16, 0, 0, p.Symbol, true); } } } }
Rename
For historic IV, use a Historic Volatility series divided by 100. Depending on the symbol you need to play with the "hvbars" to come up with a reasonable approximation to true IV.
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { string _osym; DateTime _expiry; BarHistory _obars; // the option's BarHistory int _hash = -1; UniqueList<string> _syms = new UniqueList<string>(); TimeSeries _iv; // implied volatility estimate int useSchwab; TimeSeries _hv; //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { int hvbars = 144; _hv = HV.Series(bars.Close, hvbars, 89) / 100.0; PlotTimeSeries(_hv, "HV", "HV"); StartIndex = hvbars; } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { Position opt = FindOpenPositionAllSymbols(_hash); if (opt == null) { // Use a synthetic contract. Cone states in webinar that synthetic can work for daily bars. _osym = OptionSynthetic.GetOptionsSymbol(bars, OptionType.Call, bars.Close[idx], bars.DateTimes[idx], 30, useWeeklies: false, allowExpired: true); _hash = Math.Abs(_osym.GetHashCode()); _expiry = OptionsHelper.SymbolExpiry(_osym); WriteToDebugLog("-------"); WriteToDebugLog("Buying on " + bars.DateTimes[idx]); WriteToDebugLog("Should Expire on " + _expiry); //GetHistory generates Barhistory objects based on Stock's BarHistory and Implied IV _obars = OptionSynthetic.GetHistory(bars, _osym, _hv); _syms.Add(_obars.Symbol); // Buy 1 Call. Transaction t2 = PlaceTrade(_obars, TransactionType.Buy, OrderType.Market, 0, _hash, "Buy 1 call"); t2.Quantity = 1; } else { // close the position at expiry if (bars.DateTimes[idx].AddDays(1) >= _expiry) { ClosePosition(opt, OrderType.Market, 0, "Expired"); WriteToDebugLog("Selling on " + bars.DateTimes[idx]); } } } public override void Cleanup(BarHistory bars) { // don't overload the chart with panes - plot only the last 5 contracts that were traded in Single Symbol Mode if (!Backtester.Strategy.SingleSymbolMode) return; // Indicate the trades foreach (Position p in GetPositionsAllSymbols()) { if (p.Bars == bars || _syms.IndexOf(p.Symbol) < _syms.Count - 5) continue; PlotBarHistory(p.Bars, p.Symbol); if (!p.NSF) { if (p.EntryBar > 0) DrawTextVAlign("▲", p.EntryBar, p.Bars.Low[p.EntryBar] * 0.95, VerticalAlignment.Top, WLColor.NeonBlue, 16, 0, 0, p.Symbol, true); if (p.ExitBar > 0) DrawTextVAlign("▼", p.ExitBar, p.Bars.High[p.ExitBar] * 1.05, VerticalAlignment.Bottom, WLColor.NeonFuschia, 16, 0, 0, p.Symbol, true); } } } } }
Wow, thanks Cone! Greatly appreciate the help.
****For those of you testing out, Go to Preferences -> Backtest and make sure Futures Mode Box is checked.
Your Response
Post
Edit Post
Login is required