When rotating weekly (or daily/monthly), imagine you buy every time 5 stocks with the lowest value of indicator A and short 5 stocks with the highest value of indicator A (or maybe even better indicator B.)
Would this make sense?
Let's find out.
Would this make sense?
Let's find out.
Rename
We could whip that up in a C# coded strategy first to see if it's promising.
This script is probably a good enough exercise to demonstrate that if you're going to hold short, it's not a good idea to do it "always" like in a rotation strategy.
The script holds the lowest RSI stocks long and shorts those with the highest RSI. As usual, set some Margin so you don't miss trades. You can "turn off" long or short by setting their N parameter to 0.
The script holds the lowest RSI stocks long and shorts those with the highest RSI. As usual, set some Margin so you don't miss trades. You can "turn off" long or short by setting their N parameter to 0.
CODE:
using WealthLab.Backtest; using System; using System.Text; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; using System.Linq; namespace WealthScript123 { public class LongShortRotation : UserStrategyBase { public LongShortRotation() { AddParameter("N Longs", ParameterType.Int32, 4, 0, 8, 1); AddParameter("N Shorts", ParameterType.Int32, 2, 0, 8, 1); AddParameter("Indicator Period", ParameterType.Int32, 10, 2, 20, 2); } public override void Initialize(BarHistory bars) { _NLong = Parameters[0].AsInt; _NShort = Parameters[1].AsInt; _Npositions = _NLong + _NShort; StartIndex = Parameters[2].AsInt * 3; IndicatorBase ind = RSI.Series(bars.Close, Parameters[2].AsInt); bars.Cache["indicator"] = ind; } public override void PreExecute(DateTime dt, List<BarHistory> participants) { if (participants.Count < _Npositions) return; foreach (BarHistory bh in participants) { TimeSeries ind = (TimeSeries)bh.Cache["indicator"]; int idx = GetCurrentIndex(bh); bh.UserData = ind[idx]; } //sort the candidates by value (lowest to highest) participants.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); //keep the top n candidates (lowest rsi) _longcandidates.Clear(); for (int n = 0; n < _NLong; n++) _longcandidates.Add(participants[n]); _shortcandidates.Clear(); for (int n = participants.Count - 1; n >= participants.Count - _NShort; n--) _shortcandidates.Add(participants[n]); foreach (Position pos in OpenPositionsAllSymbols) { if (pos.PositionType == PositionType.Long && !_longcandidates.Contains(pos.Bars)) ClosePosition(pos, OrderType.Market); if (pos.PositionType == PositionType.Short && !_shortcandidates.Contains(pos.Bars)) ClosePosition(pos, OrderType.Market); } foreach (BarHistory bh in _longcandidates) { if (!HasOpenPosition(bh, PositionType.Long)) { Transaction t = PlaceTrade(bh, TransactionType.Buy, OrderType.Market); t.Quantity = Math.Truncate(CurrentEquity / _Npositions / bh.Close[GetCurrentIndex(bh)]); } } foreach (BarHistory bh in _shortcandidates) { if (!HasOpenPosition(bh, PositionType.Short)) { Transaction t = PlaceTrade(bh, TransactionType.Short, OrderType.Market); t.Quantity = Math.Truncate(CurrentEquity / _Npositions / bh.Close[GetCurrentIndex(bh)]); } } } public override void Execute(BarHistory bars, int idx) { } int _Npositions = 1; int _NLong = 1; int _NShort = 1; static List<BarHistory> _longcandidates = new List<BarHistory>(); static List<BarHistory> _shortcandidates = new List<BarHistory>(); } }
I also tried the code and indeed it's not great.
Shorting a bullmarket will be quite challenging.
It will need more than an RSI. For example, only long rotating when the 50 sma is above the 200 sma. And only short rotating when 50 is below 200.
Or FOREX not stocks. And other indicators or patterns.
Still exploring.
Shorting a bullmarket will be quite challenging.
It will need more than an RSI. For example, only long rotating when the 50 sma is above the 200 sma. And only short rotating when 50 is below 200.
Or FOREX not stocks. And other indicators or patterns.
Still exploring.
Your Response
Post
Edit Post
Login is required