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