I'm wondering whether it's possible to implement a strategy that swaps one position with another one at the EOD based on some condition. Here is an example strategy of what I mean:
Swap b/w SPY and UXVY,
Based on SPY RSI(10):
If at close SPY RSI(10) > 80: If holding SPY, sell SPY and buy UXVY at close. If no holdings (only at the start of the backtesting), buy UXVY.
If at close SPY RSI(10)<= 80: If holding UXVY, sell UXVY and buy SPY at close. If no holdings (only at the start of the backtesting), buy SPY.
Basically I want to swap b/w SPY and UXVY at EOD.
Swap b/w SPY and UXVY,
Based on SPY RSI(10):
If at close SPY RSI(10) > 80: If holding SPY, sell SPY and buy UXVY at close. If no holdings (only at the start of the backtesting), buy UXVY.
If at close SPY RSI(10)<= 80: If holding UXVY, sell UXVY and buy SPY at close. If no holdings (only at the start of the backtesting), buy SPY.
Basically I want to swap b/w SPY and UXVY at EOD.
Rename
I tried the following code but it did not work as the sell and buy will be on different days.
CODE:
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript1 { public class TestStrategy : UserStrategyBase { BarHistory UVXY, SPY; int RSIWindow = 10; string previousCondition = ""; TimeSeries SPY_RSI; public override void Initialize(BarHistory bars) { UVXY = GetHistory(bars, "UVXY"); SPY = GetHistory(bars, "SPY"); SPY_RSI = RSI.Series(SPY.Close, RSIWindow); PlotTimeSeries(SPY_RSI, "SPY RSI", "RatioPane", WLColor.Coral); StartIndex = RSIWindow; } public override void Execute(BarHistory bars, int idx) { // Determine the current condition string currentCondition = DetermineCondition(idx); WriteToDebugLog($"{bars.DateString(idx)}, current condition {currentCondition}, previous condition {previousCondition}"); // If the condition has changed since the previous day, close all positions if (currentCondition != previousCondition) { WriteToDebugLog($"Condition changed. Closing all positions."); CloseAllPositions(); OpenPositionsBasedOnCondition(currentCondition, idx); previousCondition = currentCondition; } else { WriteToDebugLog($"No condition change, no position change."); } } private string DetermineCondition(int idx) { // Condition based on SPY RSI if (SPY_RSI[idx] > 80) { return "Buy UVXY"; } else { return "Buy SPY"; } } private void CloseAllPositions() { foreach (var position in OpenPositionsAllSymbols) { WriteToDebugLog($"Closing position {position.Symbol}"); ClosePosition(position, OrderType.MarketClose, 0, "Close " + position.Symbol); } } private void OpenPositionsBasedOnCondition(string condition, int idx) { WriteToDebugLog($"{condition}"); // Open new positions based on the current condition switch (condition) { case "Buy UVXY": PlaceTrade(UVXY, TransactionType.Buy, OrderType.MarketClose, 0, "Buy UVXY"); break; case "Buy SPY": PlaceTrade(SPY, TransactionType.Buy, OrderType.MarketClose, 0, "Buy SPY"); break; } } } }
WealthLab will only trade on the next bar. If these are Daily bars, then the only way you can backtest a strategy that creates a trade on the Close using the closing data is by peeking.
In your script in WeatlhLab's Editor, click on the word OrderType. It will show you a QuickRef example of how to peek in a backtest for a Sell at MarketClose exit.
In your script in WeatlhLab's Editor, click on the word OrderType. It will show you a QuickRef example of how to peek in a backtest for a Sell at MarketClose exit.
Thanks @Cone for pointing to the example. By changing
to
I was able to get what I wanted to test.
CODE:
string currentCondition = DetermineCondition(idx);
to
CODE:
string currentCondition = DetermineCondition(idx+1);
I was able to get what I wanted to test.
Re: Post #3. Is it just me or your change looks like bluntly peeking into the future and will throw an exception on the last bar?
@Eugene sorry I forgot to update the code here, locally I skipped the last bar in execute.
update: I just tried even without skipping last bar it did not throw exception.
update: I just tried even without skipping last bar it did not throw exception.
Somehow when i extended this to a three condition switch, it did not work as expected. I only see SPY positions. Any idea?
So for the above code I noticed NSF positions in the report. After i increased margin factor to 3-5 it worked fine and I see positions from all three tickers.
I guess the reason might be that sell and buy happens on the close of the same bar when a switch happens, WL might not be enforce the execution order of these trades?
Any idea @Engene, @Cone?
I guess the reason might be that sell and buy happens on the close of the same bar when a switch happens, WL might not be enforce the execution order of these trades?
Any idea @Engene, @Cone?
CODE:
private string DetermineCondition(int idx) { if (SPY_RSI[idx] > 80) { return "Buy UVXY"; } else { if (SPY_RSI[idx] < 30) { return "Buy UPRO"; } return "Buy SPY"; } }
Looks like most of the time, you'll default to buying SPY. If SPY_RSI is less than 80 and greater than 30 then you'll by SPY.
@paul1986: yes that was the rules.
Your Response
Post
Edit Post
Login is required