Overall Statistics |
Total Trades 60 Average Win 2.65% Average Loss -0.69% Compounding Annual Return 5.780% Drawdown 7.700% Expectancy 0.298 Net Profit 5.911% Sharpe Ratio 0.621 Loss Rate 73% Win Rate 27% Profit-Loss Ratio 3.87 Alpha 0.045 Beta -0.025 Annual Standard Deviation 0.071 Annual Variance 0.005 Information Ratio -0.017 Tracking Error 0.166 Treynor Ratio -1.732 Total Fees $2076.36 |
namespace QuantConnect { // Exit Manager handles scans for when posisions have hit targets and / or stops public partial class SwingSystem : QCAlgorithm { public class ExitManager { private SwingSystem _algorithm; private Dictionary<string, decimal> ShortStops = new Dictionary<string, decimal>(); private Dictionary<string, decimal> LongStops = new Dictionary<string, decimal>(); private decimal _atrmultipler; public ExitManager(SwingSystem algorithm) { this._atrmultipler = algorithm.ATRmultiplier; this._algorithm = algorithm; foreach (string instrument in algorithm.Instruments) { this.ShortStops.Add(instrument, Convert.ToDecimal(0)); this.LongStops.Add(instrument, Convert.ToDecimal(0)); } } public void UpdateStops(TradeBars bars) { //Trailing ATR * 3 stops. Only move in direction of trade so losses are minimized and R is constant foreach (string instrument in this._algorithm.Instruments) { //Only update stops where there is no active position if (this._algorithm.Portfolio[instrument].Quantity > 0) { this.ShortStops[instrument] = bars[instrument].Price + this._algorithm.ATRs[instrument]*this._atrmultipler; // if (bars[instrument].Price - this._algorithm.ATRs[instrument]*this._atrmultipler > this.LongStops[instrument]) { // this.LongStops[instrument] = bars[instrument].Price - this._algorithm.ATRs[instrument]*this._atrmultipler; // } } else if (this._algorithm.Portfolio[instrument].Quantity < 0) { this.LongStops[instrument] = bars[instrument].Price - this._algorithm.ATRs[instrument]; // if (bars[instrument].Price + this._algorithm.ATRs[instrument]*this._atrmultipler < this.ShortStops[instrument]) { // this.ShortStops[instrument] = bars[instrument].Price + this._algorithm.ATRs[instrument]*this._atrmultipler; // } } else { this.ShortStops[instrument] = bars[instrument].Price + this._algorithm.ATRs[instrument]*this._atrmultipler; this.LongStops[instrument] = bars[instrument].Price - this._algorithm.ATRs[instrument]*this._atrmultipler; } } } public void ExecuteExits(TradeBars bars) { foreach (string instrument in this._algorithm.Instruments) { //If we're Long if (this._algorithm.Portfolio[instrument].Quantity > 0) { //Check if we've hit stops if (bars[instrument].Low < this.LongStops[instrument]) { this._algorithm.Log("Long stop loss reached at price " + bars[instrument].Price + " With stop loss at " + this.LongStops[instrument]); this._algorithm.Liquidate(instrument); } //Check if RSI has returned to parity or price has crossed EMA if (bars[instrument].High > this._algorithm.LongEmas[instrument] || this._algorithm.RSIs[instrument] > 50) { this._algorithm.Liquidate(instrument); this._algorithm.Log("Target reached"); } } //If we're short if (this._algorithm.Portfolio[instrument].Quantity <0) { //Check if we've hit stops if (bars[instrument].High > this.ShortStops[instrument]) { this._algorithm.Log("Short stop loss reached at price " + bars[instrument].Price + " With stop loss at " + this.ShortStops[instrument]); this._algorithm.Liquidate(instrument); } //Check if RSI has returned to parity or price has crossed EMA if (bars[instrument].Low < this._algorithm.LongEmas[instrument] || this._algorithm.RSIs[instrument] < 50) { this._algorithm.Liquidate(instrument); this._algorithm.Log("Target reached"); } } } } public decimal GetShortStop(string instrument) { return this.ShortStops[instrument]; } public decimal GetLongStop(string instrument) { return this.LongStops[instrument]; } } } }
namespace QuantConnect { // // Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all // files use "public partial class" if you want to split up your algorithm namespace into multiple files. // public partial class SwingSystem : QCAlgorithm { public class EntryManager { private SwingSystem _algorithm; public EntryManager(SwingSystem algorithm) { this._algorithm = algorithm; } public void UpdateBounds() { } public void ExecuteEntries(TradeBars bars, FilterManager filters) { foreach (string instrument in this._algorithm.Instruments) { if (this._algorithm.Portfolio[instrument].Quantity != 0) { break; } //Check that the vol filter passes, that we have no current holdings before running entry check //and that we are in a ranging market if (filters.GetVolFilter(instrument) && this._algorithm.Portfolio[instrument].Quantity == 0 && filters.GetDaysInRange(instrument) >= 20) { //If we're above the EMA + 3ATRS and the RSI has risen above 70, go short. if (bars[instrument].Price > (this._algorithm.LongEmas[instrument] + (decimal)3 * this._algorithm.ATRs[instrument]) && this._algorithm.RSIs[instrument] > 70) { this._algorithm.Log("Short order placed. RSI is " + this._algorithm.RSIs[instrument] + " Days in range is " + filters.GetDaysInRange(instrument)); this._algorithm.Order(instrument, -(this._algorithm.PositionSizes[instrument])); } //If we are below the EMA - 3ATRs and the RSI is below 30, go long if (bars[instrument].Price < (this._algorithm.LongEmas[instrument] - (decimal)3 * this._algorithm.ATRs[instrument]) && this._algorithm.RSIs[instrument] < 30) { this._algorithm.Log("Long order placed. RSI is " + this._algorithm.RSIs[instrument] + " Days in range is " + filters.GetDaysInRange(instrument)); this._algorithm.Order(instrument, this._algorithm.PositionSizes[instrument]); } } } } } } }
namespace QuantConnect { // // Class to keep track of market conditions for each instrument so that only markets which are below // a certain level of ATR volatility are traded. public partial class SwingSystem : QCAlgorithm { public class FilterManager { private SwingSystem _algorithm; private Dictionary<string, int> TrendFilters = new Dictionary<string, int>(); private Dictionary<string, bool> VolFilters = new Dictionary<string, bool>(); private Dictionary<string, int> DaysInRange = new Dictionary<string, int>(); public int GetTrendFilter(string instrument) { return this.TrendFilters[instrument]; } public bool GetVolFilter(string instrument) { return this.VolFilters[instrument]; } public int GetDaysInRange(string instrument) { return this.DaysInRange[instrument]; } public FilterManager(SwingSystem algorithm) { this._algorithm = algorithm; foreach (string instrument in algorithm.Instruments) { this.TrendFilters.Add(instrument, 0); this.VolFilters.Add(instrument, false); this.DaysInRange.Add(instrument, 0); } } public void UpdateFilters(TradeBars bars) { foreach (string instrument in this._algorithm.Instruments) { this.VolFilters[instrument] = true; //Check that the market is ranging //We define this as the price being within 5% of the 100d EMA if (bars[instrument].Price > this._algorithm.LongEmas[instrument]) { if (bars[instrument].High < ((decimal)1.05 * this._algorithm.LongEmas[instrument])) { this.DaysInRange[instrument] += 1; } else { if (this.DaysInRange[instrument] >= 20) { this.DaysInRange[instrument] = 15; } else if (this.DaysInRange[instrument] >= 5) { this.DaysInRange[instrument] -= 5; } else { this.DaysInRange[instrument] = 0; } } } if (bars[instrument].Price < this._algorithm.LongEmas[instrument]) { if (bars[instrument].Low > (this._algorithm.LongEmas[instrument] * (decimal)0.95)) { this.DaysInRange[instrument] += 1; } else { if (this.DaysInRange[instrument] >= 20) { this.DaysInRange[instrument] = 15; } else if (this.DaysInRange[instrument] >= 5) { this.DaysInRange[instrument] -= 5; } else { this.DaysInRange[instrument] = 0; } } } //Check if DaysInRange is in excess of 20 if (this.DaysInRange[instrument] >= 20) { this.TrendFilters[instrument] = 1; } else { this.TrendFilters[instrument] = 0; } //Update vol filters // if (this._algorithm.ATRs[instrument] / bars[instrument].Price < (decimal)0.02) { // this.VolFilters[instrument] = true; // } // if (this._algorithm.ATRs[instrument] / bars[instrument].Price > (decimal)0.02) { // this.VolFilters[instrument] = false; // } } } } } }
namespace QuantConnect { // // Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all // files use "public partial class" if you want to split up your algorithm namespace into multiple files. // public partial class SwingSystem : QCAlgorithm { public class PositionSizeManager { private SwingSystem _algorithm; public PositionSizeManager(SwingSystem algorithm) { this._algorithm = algorithm; } public void UpdatePositionSizes(TradeBars bars) { //Position size is set so that 2% of capital is equivalent to a 1ATR move. foreach (string instrument in this._algorithm.Instruments) { var onepercent = this._algorithm.Portfolio.TotalPortfolioValue/50; var atrs = bars[instrument].Price / (3*this._algorithm.ATRs[instrument]); var positionsize = onepercent * atrs; this._algorithm.PositionSizes[instrument] = (int)positionsize; } } } } }
namespace QuantConnect { /* * * Swing system designed to only trade markets that have been within 5% of the 100d EMA for 20 days or more * */ public partial class SwingSystem : QCAlgorithm { //Set up global variables //Set all the assets we want to following public List<string> Instruments = new List<string>(); public Dictionary<string, ExponentialMovingAverage> LongEmas = new Dictionary<string, ExponentialMovingAverage>(); public Dictionary<string, AverageTrueRange> ATRs = new Dictionary<string, AverageTrueRange>(); public Dictionary<string, int> PositionSizes = new Dictionary<string, int>(); public Dictionary<string, RelativeStrengthIndex> RSIs = new Dictionary<string, RelativeStrengthIndex>(); // set up objects public PositionSizeManager positionSizeManager; public ExitManager exitManager; public EntryManager entryManager; public FilterManager filterManager; public decimal ATRmultiplier = Convert.ToDecimal(1); //Initialize the data and resolution you require for your strategy: public override void Initialize() { //initialise classes and fill instruments List // Instruments.Add("GBPUSD"); // Instruments.Add("EURUSD"); // Instruments.Add("USDJPY"); Instruments.Add("USDCAD"); Instruments.Add("USDCHF"); // Instruments.Add("AUDUSD"); // Instruments.Add("NZDUSD"); exitManager = new ExitManager(this); entryManager = new EntryManager(this); positionSizeManager = new PositionSizeManager(this); filterManager = new FilterManager(this); SetWarmup(100); foreach (string instrument in Instruments) { AddForex(instrument, Resolution.Daily); var longema = EMA(instrument, 100); LongEmas.Add(instrument, longema); var rsi = RSI(instrument, 10, MovingAverageType.Simple, Resolution.Daily); RSIs.Add(instrument, rsi); var atr = ATR(instrument, 20, MovingAverageType.Simple, Resolution.Daily); ATRs.Add(instrument, atr); PositionSizes.Add(instrument, 0); } //Start and End Date range for the backtest: SetStartDate(2016, 01, 01); SetEndDate(2016, 08, 01); // SetEndDate(DateTime.Now.Date.AddDays(-1)); //Cash allocation SetCash(1000000); } //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol. public void OnData(TradeBars data) { if (IsWarmingUp) { return; } foreach (string instrument in Instruments) { if (!LongEmas[instrument].IsReady) { return; } if (!data.ContainsKey(instrument)) { return; } } positionSizeManager.UpdatePositionSizes(data); filterManager.UpdateFilters(data); entryManager.UpdateBounds(); exitManager.UpdateStops(data); exitManager.ExecuteExits(data); Schedule.On(DateRules.EveryDay(), TimeRules.AfterMarketOpen("USDCHF", 5), () => { entryManager.ExecuteEntries(data, filterManager); }); } } }