| Overall Statistics |
|
Total Trades 396 Average Win 2.31% Average Loss -2.46% Compounding Annual Return 13.079% Drawdown 42.900% Expectancy 0.258 Net Profit 209.711% Sharpe Ratio 0.516 Loss Rate 35% Win Rate 65% Profit-Loss Ratio 0.94 Alpha 0.108 Beta -0.025 Annual Standard Deviation 0.206 Annual Variance 0.043 Information Ratio 0.224 Tracking Error 0.273 Treynor Ratio -4.245 Total Fees $798.94 |
namespace QuantConnect
{
public class Mundo : QCAlgorithm
{
//List of Currencies you would like to trade and get the indexes for
List<string> _symbols = new List<string>() { "EURUSD", "GBPUSD", "AUDUSD", "NZDUSD"};
TradeBars _bars = new TradeBars();
private Dictionary<string, SymbolData> _symbolData = new Dictionary<string, SymbolData>();
public readonly int RollingWindowSize = 2;
public readonly TimeSpan BarPeriod = TimeSpan.FromDays(1);
//parameters
int _normPeriod = 60;
int _period = 20;
//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(2007, 5, 1);
SetEndDate(DateTime.Now.Date.AddDays(-1));
//Cash allocation
SetCash(30000);
// initialize data for all the symbols
foreach (var symbol in _symbols)
{
_symbolData.Add(symbol, new SymbolData(symbol, SecurityType.Forex, BarPeriod, RollingWindowSize));
}
//Set forex securities and Consolidate all the data
foreach (var kvp in _symbolData)
{
var symbolData = kvp.Value;
//AddSecurity(symbolData.SecurityType, symbolData.Symbol, Resolution.Hour);
AddForex(symbolData.Symbol, Resolution.Hour, "fxcm");
// define a consolidator to consolidate data for this symbol on the requested period
var consolidator = new TradeBarConsolidator(BarPeriod);
// define indicators
symbolData._sd = new StandardDeviation(_period);
symbolData._min = new Minimum(_normPeriod);
symbolData._max = new Maximum(_normPeriod);
//update indicators
consolidator.DataConsolidated += (sender, bar) =>
{
// 'bar' here is our newly consolidated data
symbolData._min.Update(bar.Time, symbolData._portfolio);
symbolData._max.Update(bar.Time, symbolData._portfolio);
symbolData._sd.Update(bar.Time, bar.Close);
// we're also going to add this bar to our rolling window so we have access to it later
symbolData.Bars.Add(bar);
};
// we need to add this consolidator so it gets auto updates
SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator);
}
}
//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;
decimal _beta = 0;
decimal _prt = 0;
// Calculate total SD
foreach (var _data in _symbolData.Values)
{
if (!_data._sd.IsReady) return;
if (_data._sd != 0)
{
_totalSd += _data._sd;
_beta += _data._sd;
}
}
foreach (var _data in _symbolData.Values)
{
//make portfolio with Mundo index beta weights
if (_beta != 0) _prt += _bars[_data.Symbol].Close * _data._sd / (_beta / 4m);
}
foreach (var _data in _symbolData.Values)
{
_data._portfolio = _prt;
// Do a basic 0-1 Min-Max Normalization to normalize all the values
if ((_data._max - _data._min) != 0) _data._norm = (_prt - _data._min) / (_data._max - _data._min);
//------------------------------------------------------------------------------------------ EXITS
if (Portfolio[_data.Symbol].IsLong && _data._norm > 1m)
{
Liquidate();
}
if (Portfolio[_data.Symbol].IsShort && _data._norm < 0m)
{
Liquidate();
}
//------------------------------------------------------------------------------------------ ENTRIES
if (!Portfolio[_data.Symbol].Invested && _data._norm > 0 && _data._prenorm < 0)
{
if ((_beta / 4m) != 0 && _data._sd != 0) SetHoldings(_data.Symbol, 0.4m / (_data._sd / (_beta / 4m)));
}
if (!Portfolio[_data.Symbol].Invested && _data._norm < 1m && _data._prenorm > 1m)
{
if ((_beta / 4m) != 0 && _data._sd != 0) SetHoldings(_data.Symbol, -0.6m / (_data._sd / (_beta / 4m)));
}
_data._prenorm = _data._norm; //Keep track of the previous normalized values
}
} // end of 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;
}
}
//Create a class to manage all the Symbol Data
class SymbolData
{
//stuff
public readonly string Symbol;
public readonly SecurityType SecurityType;
public readonly RollingWindow<TradeBar> Bars;
public readonly TimeSpan BarPeriod;
//indcators
public StandardDeviation _sd;
public Minimum _min;
public Maximum _max;
public decimal _portfolio;
public decimal _norm;
public decimal _prenorm;
// Constructor for the class
public SymbolData(string symbol, SecurityType securityType, TimeSpan barPeriod, int windowSize)
{
Symbol = symbol;
SecurityType = securityType;
BarPeriod = barPeriod;
Bars = new RollingWindow<TradeBar>(windowSize);
_portfolio = new decimal();
_norm = new decimal();
_prenorm = new decimal();
}
public bool IsReady
{
get
{
return Bars.IsReady
&& _sd.IsReady
&& _min.IsReady
&& _max.IsReady
;
}
}
// public bool WasJustUpdated(DateTime current)
// {
// return Bars.Count > 0 && Bars[0].Time == current - BarPeriod;
//}
}
} // end of algorithm
}