| Overall Statistics |
|
Total Trades 403 Average Win 9.09% Average Loss -2.88% Compounding Annual Return 17.898% Drawdown 53.500% Expectancy 0.321 Net Profit 284.257% Sharpe Ratio 0.523 Loss Rate 68% Win Rate 32% Profit-Loss Ratio 3.15 Alpha 0 Beta 0 Annual Standard Deviation 0.432 Annual Variance 0.187 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $806.00 |
namespace QuantConnect
{
public class FXMomentumTests : QCAlgorithm
{
List<string> _symbols = new List<string>() { "EURUSD", "AUDUSD", "EURJPY", "GBPAUD", "NZDUSD", "USDCAD", "USDJPY" };
TradeBars _bars = new TradeBars();
private Dictionary<string, SymbolData> _symbolData = new Dictionary<string, SymbolData>();
decimal _totalLots = 150m;
//int _rebalancingPeriod = 30;
//Initialize the data and resolution you require for your strategy:
public override void Initialize()
{
//Start and End Date range for the backtest:
SetStartDate(2007, 4, 1);
SetEndDate(2015, 6, 1);
//SetEndDate(DateTime.Now.Date.AddDays(-1));
//Cash allocation
SetCash(10000);
foreach (var symbol in _symbols)
{
//Add as many securities as you like. All the data will be passed into the event handler:
AddSecurity(SecurityType.Forex, symbol, Resolution.Daily);
_symbolData.Add(symbol, new SymbolData(symbol, this));
}
}
//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)
{
UpdateBars(data);
if (_bars.Count != _symbols.Count) return;
decimal _totalSd = 0;
foreach (var _data in _symbolData.Values)
{
if(!_data._sd.IsReady) return;
if(!_data._smaF.IsReady) return;
if(!_data._smaS.IsReady) return;
if(_data._sd != 0) _totalSd += _data._sd;
}
foreach (var _data in _symbolData.Values)
{
//if(_data._sd != 0) Plot("Indicator "+_data.Symbol, "w", _data._sd);
//------------------------------------------------------------------------------------------ EXITS
if(Portfolio[_data.Symbol].IsLong && _data._smaF < _data._smaS)
{
Liquidate(_data.Symbol);
}
if(Portfolio[_data.Symbol].IsShort && _data._smaF > _data._smaS)
{
Liquidate(_data.Symbol);
}
decimal _qty = ((_data._sd) / _totalSd) * _totalLots;
Plot("Indicator "+_data.Symbol, "w", _qty);
//------------------------------------------------------------------------------------------ ENTRIES
if(!Portfolio[_data.Symbol].Invested && _data._smaF > _data._smaS)
{
SetHoldings(_data.Symbol, _qty);
_data.lastrebalance = _bars[_data.Symbol].Time;
}
if(!Portfolio[_data.Symbol].Invested && _data._smaF < _data._smaS)
{
SetHoldings(_data.Symbol, -_qty);
_data.lastrebalance = _bars[_data.Symbol].Time;
}
//------------------------------------------------------------------------------------------ REBALANCE
/*if(Portfolio[_data.Symbol].IsLong && (_bars[_data.Symbol].Time - _data.lastrebalance).TotalDays >= _rebalancingPeriod)
{
SetHoldings(_data.Symbol, _qty);
_data.lastrebalance = _bars[_data.Symbol].Time;
}
Log("thist "+_bars[_data.Symbol].Time+" lastt "+_data.lastrebalance);
if(Portfolio[_data.Symbol].IsShort && (_bars[_data.Symbol].Time - _data.lastrebalance).TotalDays >= _rebalancingPeriod)
{
SetHoldings(_data.Symbol, -_qty);
_data.lastrebalance = _bars[_data.Symbol].Time;
}*/
}
} // end ondata
//Update the global "_bars" object
private void UpdateBars(TradeBars data)
{
foreach (var bar in data.Values)
{
if (!_bars.ContainsKey(bar.Symbol))
{
_bars.Add(bar.Symbol, bar);
}
_bars[bar.Symbol] = bar;
}
}
class SymbolData
{
//parameters
int _fastPeriod = 20;
int _slowPeriod = 120;
public DateTime lastrebalance;
public readonly string Symbol;
public readonly SimpleMovingAverage _smaS;
public readonly SimpleMovingAverage _smaF;
public readonly StandardDeviation _sd;
public decimal _q;
public SymbolData(string symbol, QCAlgorithm algorithm)
{
Symbol = symbol;
_smaF = algorithm.SMA(symbol, _fastPeriod, Resolution.Daily);
_smaS = algorithm.SMA(symbol, _slowPeriod, Resolution.Daily);
_sd = algorithm.STD(symbol, _fastPeriod, Resolution.Daily);
_q = new decimal();
lastrebalance = new DateTime();
}
}
} // close algo
}