Code that does not buy so many positions!! 😂
The way to prevent NSF positions is to make sure you have enough simulated capital to take all of the positions. Increase the starting capital and or reduce the positions size and you’ll see that count go down.
The way to prevent NSF positions is to make sure you have enough simulated capital to take all of the positions. Increase the starting capital and or reduce the positions size and you’ll see that count go down.
Just to add, if you're using market orders then selecting "Market open next bar" may also reduce the number of NSFs.
Videos can be helpful. Please explain further how the NSF's are handled, specifically:
https://youtu.be/HXA-AetQ3Jk
I notice in some strategies with non-zero NSF position counts shown in the Metrics report, there are NSF icons (a brown circle next to a symbol in the Signals page), however in other strategies which also have many non-zero NSF position counts shown after a backtest, there are no NSF icons. The advanced setting "Retain NSF positions" is checked in all instances.
https://youtu.be/HXA-AetQ3Jk
I notice in some strategies with non-zero NSF position counts shown in the Metrics report, there are NSF icons (a brown circle next to a symbol in the Signals page), however in other strategies which also have many non-zero NSF position counts shown after a backtest, there are no NSF icons. The advanced setting "Retain NSF positions" is checked in all instances.
Those non-zero NSF position counts in your backtest include NSF trades in the past, so that there may be no current NSF situation on the Signals tab.
QUOTE:
What kind of code would be needed to prevent NSF positions ?
There isn't a one-fits-all answer for that, but I'm thinking of a programming pattern like this for market orders:
1. Create a static List<BarHistory> _entries to store a list of entries on a given bar.
2. When you have a signal, add it to the List, and save a value in the UserData property to use like Transaction.Weight for sorting.
3. The trick is to not PlaceTrades (for entries) until PostExecute. There, sort the _entries list by the UserData.
4. Determine how many new positions can be placed based on the sizing and Equity. To control this better, you should probably have a number of max Positions and use it for Equity % sizing.
5. Place just those trades.
Edit: I'm mocking up an exacmple now.. hang tight.
Maybe it's a little difficult to follow, but hopefully not!
Note!
This won't save you from NSFs for prices that are gapping. Use a little margin (maybe 1.1) to account for gaps.
Note!
This won't save you from NSFs for prices that are gapping. Use a little margin (maybe 1.1) to account for gaps.
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript2 { public class ReduceNSF : UserStrategyBase { static List<BarHistory> _entrySignals = new List<BarHistory>(); static List<BarHistory> _exitSignals = new List<BarHistory>(); SMA _sma; RSI _rsi; int _maxPositions; public ReduceNSF() { AddParameter("Max Positions", ParameterTypes.Int32, 10, 2, 20, 1); AddParameter("Period", ParameterTypes.Int32, 5, 5, 15, 5); } public override void Initialize(BarHistory bars) { _maxPositions = Parameters[0].AsInt; int period = Parameters[1].AsInt; StartIndex = period; _sma = SMA.Series(bars.Close, period); _rsi = RSI.Series(bars.Close, 10); PlotIndicatorLine(_sma); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { if (!HasOpenPosition(bars, PositionType.Long)) { // Entry logic if (bars.Close.CrossesOver(_sma, idx)) { bars.UserData = _rsi[idx]; _entrySignals.Add(bars); } } else { // Exit logic if (bars.Close.CrossesUnder(_sma, idx)) { _exitSignals.Add(bars); PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } } public override void PostExecute(DateTime dt, List<BarHistory> participants) { //sort the entries list from lower to higher UserData. For higher to lower, change to .Sort(b, a) _entrySignals.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); //how many signals can we take? int maxSignals = _maxPositions - OpenPositionsAllSymbols.Count + _exitSignals.Count; int entries = Math.Min(maxSignals, _entrySignals.Count); // WriteToDebugLog(dt.ToShortDateString() + "\t" + _entrySignals.Count.ToString() + "\t" // + _exitSignals.Count.ToString() + "\t" + entries.ToString() ); //place the trades with the lowest RSI from the sorted list and size the tranactions string sizes = ""; for (int n = 0; n < entries; n++) { BarHistory bh = _entrySignals[n]; Transaction t = PlaceTrade(bh, TransactionType.Buy, OrderType.Market); int bar = GetCurrentIndex(bh); t.Quantity = Math.Floor(CurrentCash / entries / bh.Close[bar]); sizes += string.Format("{0} [{1}], ", bh.Symbol, t.Quantity); } //print out the symbols and sizes for these entries if (entries > 0) WriteToDebugLog(sizes); _entrySignals.Clear(); _exitSignals.Clear(); } } }
Your Response
Post
Edit Post
Login is required