Overall Statistics
Total Trades
267
Average Win
3.22%
Average Loss
-2.35%
Compounding Annual Return
1395.634%
Drawdown
25.700%
Expectancy
0.550
Net Profit
388.278%
Sharpe Ratio
2.706
Loss Rate
35%
Win Rate
65%
Profit-Loss Ratio
1.37
Alpha
2.214
Beta
-0.494
Annual Standard Deviation
0.797
Annual Variance
0.636
Information Ratio
2.515
Tracking Error
0.813
Treynor Ratio
-4.369
Total Fees
$0.00
namespace QuantConnect 
{   
    public class ForexMovingAvgCross : QCAlgorithm
    {
    	//Create list of currency pairs to be traded
    	List<string> Pairs = new List<string>
        {
        	"AUDUSD",
        	"EURUSD",
        	"NZDUSD",
        	"USDCAD"
        };
        
        //Prepare a list for holding instances of the SymbolData object.
        List<SymbolData> SymbolData = new List<SymbolData>();
            
        //Initialize the data and resolution you require for your strategy:
        public override void Initialize() 
        {
        	
        	//Override the default fee model with Fxcm's
        	SetBrokerageModel(BrokerageName.OandaBrokerage);
			
            //Start and End Date range for the backtest:
            SetStartDate(2012, 1, 1);         
            SetEndDate(2012, 8, 1);
            
            //Cash allocation
            SetCash(25000);
            
            //Iterate through the pairs list and prepare data
            foreach (var symbol in Pairs)
            {
            	//add the pair to algorithm
            	AddForex(symbol, Resolution.Minute, Market.Oanda);
            	
            	//prepare the indicators required for the strategy
            	var atr = ATR(symbol, 5, MovingAverageType.Simple, Resolution.Minute);
            	//var fastMA = SMA(symbol, 10, Resolution.Minute);
            	var myPsar = PSAR(symbol, 0.02m, 0.02m, 0.2m);
            	var myHigh = SMA(symbol, 1, selector: m => ((QuoteBar)m).High);
            	var myLow = SMA(symbol, 1, selector: m => ((QuoteBar)m).Low);
            	var myAdx = ADX(symbol, 14, Resolution.Minute);
            	var myRsi = RSI(symbol, 14, MovingAverageType.Exponential, Resolution.Minute);
            	var fastMa = EMA(symbol, 14, selector: m => ((QuoteBar)m).Open);
            	var slowMa = EMA(symbol, 14, selector: m => ((QuoteBar)m).Close);

            	/*Intialize an object representing the pair to and add 
            	it to the symboldata list */
            	SymbolData.Add(new SymbolData
            	{
            		Symbol = symbol,
            		Atr = atr,
            		MyRsi = myRsi,
            		MyPsar = myPsar,
            		MyHigh = myHigh,
            		MyLow = myLow,
            		Risk = .0005m,
            		MyAdx = myAdx,
            		FastMa = fastMa,
            		SlowMa = slowMa,
            	});
            }
            
            Schedule.On(DateRules.EveryDay(Pairs[0]), TimeRules.AfterMarketOpen(Pairs[0], 0), () =>
            {
            	ManageTrades();
            });
        }

        //Data Event Handler: 
        public void OnData(TradeBars data) 
        {
        }
        public void ManageTrades()
        {
        	//Iterate through each currency pair
            foreach(var symbolObj in SymbolData)
            {
            	if (symbolObj.Atr == 0m )
            	{
            		continue;
            	}
            	//If the current pair is flat
            	if (!Portfolio[symbolObj.Symbol].Invested)
            	{
            		//Check for long entry criteria
            		if (((symbolObj.MyLow < symbolObj.MyPsar) && (symbolObj.MyAdx > 25) && (symbolObj.MyRsi < 45)))// && (symbolObj.FastMa > symbolObj.SlowMa))))
            		{
            			MarketOrder(symbolObj.Symbol, symbolObj.AdjustedLotSize(Portfolio));
            		}
            		//else check for short entry criteria
            		else if (((symbolObj.MyHigh > symbolObj.MyPsar) && (symbolObj.MyAdx > 25) && (symbolObj.MyRsi > 55)))// && (symbolObj.FastMa < symbolObj.SlowMa))))
            		{
            			MarketOrder(symbolObj.Symbol, -symbolObj.AdjustedLotSize(Portfolio));
            		}
            	}
            	//If the portfolio holds a long position
            	else if (Portfolio[symbolObj.Symbol].IsLong)
            	{	
            		//Exit long
            		if (symbolObj.MyHigh > symbolObj.MyPsar)
            		{
            			//Liquidate
            			Liquidate(symbolObj.Symbol);
            			//MarketOrder(symbolObj.Symbol, -symbolObj.AdjustedLotSize(Portfolio));
            		}
            	}
            	//If the portfolio holds a short position
            	else if (Portfolio[symbolObj.Symbol].IsShort)
        		{
        			//Exit short
            		if (symbolObj.MyLow < symbolObj.MyPsar)
            		{
            			//Liquidate
            			Liquidate(symbolObj.Symbol);
            			//MarketOrder(symbolObj.Symbol, symbolObj.AdjustedLotSize(Portfolio));
            		}
            	}
            }
        }
    }
    class SymbolData
	{
	    public string Symbol;
	    
    	public AverageTrueRange Atr { get; set; }
    	public RelativeStrengthIndex MyRsi { get; set; }
    	public SimpleMovingAverage MyLow { get; set; }
    	public ExponentialMovingAverage FastMa { get; set; }
    	public ExponentialMovingAverage SlowMa { get; set; }
    	public SimpleMovingAverage MyHigh { get; set; }
	    public ParabolicStopAndReverse MyPsar { get; set; }
	    public decimal Risk { get; set; }
	    public AverageDirectionalIndex MyAdx { get; set; }////REMOVE IF DONT WORK

		// Calculate the adjusted lot size based on risk managment criteria
    	public int AdjustedLotSize(SecurityPortfolioManager Portfolio)
    	{
    		//get the current account value
    		var equity = Portfolio.TotalPortfolioValue;
    		//determine the lotsize for the current pair
    		var lotSize = Portfolio.Securities[Symbol].SymbolProperties.LotSize;
    		//obtain the conversion rate for the pair
    		var conversionRate = Portfolio.Securities[Symbol].QuoteCurrency.ConversionRate;
    		var adjustedSize = 10000m;
    		
    		adjustedSize = (Risk * equity)/(Atr * conversionRate);

    		adjustedSize = Math.Floor(adjustedSize/lotSize) * lotSize;
    		
	        return (int)adjustedSize;
	    }
    }
}