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);
				});
				
				
			
				
				
				
				
			
			
			
            
        }
    }
}