Overall Statistics |
Total Trades 368 Average Win 1.81% Average Loss -0.49% Compounding Annual Return 14.294% Drawdown 14.300% Expectancy 0.545 Net Profit 65.176% Sharpe Ratio 0.769 Loss Rate 67% Win Rate 33% Profit-Loss Ratio 3.69 Alpha 0.102 Beta -0.014 Annual Standard Deviation 0.132 Annual Variance 0.017 Information Ratio 0.373 Tracking Error 0.265 Treynor Ratio -7.375 Total Fees $481.92 |
namespace QuantConnect { public class ForexMovingAvgCross : QCAlgorithm { //Create list of currency pairs to be traded List<string> Pairs = new List<string> { "AUDUSD", "EURCHF", "EURGBP", "EURJPY", "EURUSD", "GBPUSD", "NZDUSD", "USDCAD", "USDCHF", "USDJPY" }; //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.FxcmBrokerage); //Start and End Date range for the backtest: SetStartDate(2007, 4, 1); SetEndDate(2010, 12, 31); //Cash allocation SetCash(100000); //Iterate through the pairs list and prepare data foreach (var symbol in Pairs) { //add the pair to algorithm AddForex(symbol, Resolution.Hour, Market.FXCM); //prepare the indicators required for the strategy var atr = ATR(symbol, 100, MovingAverageType.Simple, Resolution.Daily); var fastMA = SMA(symbol, 10, Resolution.Daily); var slowMA = SMA(symbol, 100, Resolution.Daily); /*Intialize an object representing the pair to and add it to the symboldata list */ SymbolData.Add(new SymbolData { Symbol = symbol, Atr = atr, FastMA = fastMA, SlowMA = slowMA, Risk = .002m //logic can be subsituted here to set per pair risk metrics }); } Schedule.On(DateRules.EveryDay(Pairs[0]), TimeRules.AfterMarketOpen(Pairs[0], 0), () => { ManageTrades(); }); } //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) { } 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.FastMA >= symbolObj.SlowMA) { MarketOrder(symbolObj.Symbol, symbolObj.AdjustedLotSize(Portfolio)); } //Otherwise enter short position else { MarketOrder(symbolObj.Symbol, -symbolObj.AdjustedLotSize(Portfolio)); } } //If the portfolio holds a long position else if (Portfolio[symbolObj.Symbol].IsLong) { //Check for reversal criteria if (symbolObj.FastMA < symbolObj.SlowMA) { //Liquidate and send short order Liquidate(symbolObj.Symbol); MarketOrder(symbolObj.Symbol, -symbolObj.AdjustedLotSize(Portfolio)); } } //If the portfolio holds a short position else if (Portfolio[symbolObj.Symbol].IsShort) { //Check for reversal criteria if (symbolObj.FastMA >= symbolObj.SlowMA) { //Liquidate and send buy order Liquidate(symbolObj.Symbol); MarketOrder(symbolObj.Symbol, symbolObj.AdjustedLotSize(Portfolio)); } } } } } class SymbolData { public string Symbol; public AverageTrueRange Atr { get; set; } public SimpleMovingAverage FastMA { get; set; } public SimpleMovingAverage SlowMA { get; set; } public decimal Risk { get; set; } // 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; } } }