Overall Statistics |
Total Trades 702 Average Win 3.30% Average Loss -3.02% Compounding Annual Return 16.712% Drawdown 57.900% Expectancy 0.142 Net Profit 253.664% Sharpe Ratio 0.526 Loss Rate 45% Win Rate 55% Profit-Loss Ratio 1.09 Alpha 0.145 Beta 0.003 Annual Standard Deviation 0.276 Annual Variance 0.076 Information Ratio 0.248 Tracking Error 0.328 Treynor Ratio 41.928 Total Fees $1404.99 |
namespace QuantConnect { public class Mundo : QCAlgorithm { List<string> _symbols = new List<string>() { "EURUSD", "GBPUSD", "AUDUSD", "NZDUSD", "USDCAD", "USDCHF" }; 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 = 40; int _period = 20; decimal _size = 0.2m; //how many symbols in portfolio decimal _syms = 6; //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); // initialize data foreach (var symbol in _symbols) { _symbolData.Add(symbol, new SymbolData(symbol, SecurityType.Forex, BarPeriod, RollingWindowSize)); } foreach(var kvp in _symbolData) { var symbolData = kvp.Value; AddSecurity(symbolData.SecurityType, symbolData.Symbol, Resolution.Hour); // 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._portsd = 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); symbolData._portsd.Update(bar.Time, symbolData._portfolio); // 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; 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/_syms); } Plot("Cash", "prtSMAF", Portfolio.Cash); Plot("Portfolio curve", "prt", _prt); foreach (var _data in _symbolData.Values) { _data._portfolio = _prt; if((_data._max - _data._min) != 0) _data._norm = (_prt - _data._min)/(_data._max - _data._min); //Plot("Normalized curve", "n", _data._norm); //------------------------------------------------------------------------------------------ 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 //&& (_bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Monday //|| _bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Tuesday )//) { if((_beta/_syms) != 0 && _data._portsd != 0) SetHoldings(_data.Symbol, _size/(_data._sd/(_beta/_syms))*(1/_data._portsd)); //Log("Opened"); } if(!Portfolio[_data.Symbol].Invested && _data._norm < 1m && _data._prenorm > 1m //&& (_bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Monday //|| _bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Tuesday )//) { if((_beta/_syms) != 0 && _data._portsd != 0) SetHoldings(_data.Symbol, -_size/(_data._sd/(_beta/_syms))*(1/_data._portsd)); } //some prev value _data._prenorm = _data._norm; } } // 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 { //stuff public readonly string Symbol; public readonly SecurityType SecurityType; public readonly RollingWindow<TradeBar> Bars; public readonly TimeSpan BarPeriod; //indcators public StandardDeviation _sd; public StandardDeviation _portsd; public Minimum _min; public Maximum _max; public decimal _portfolio; public decimal _norm; public decimal _prenorm; public SymbolData(string symbol, SecurityType securityType, TimeSpan barPeriod, int windowSize) //, QCAlgorithm algorithm { 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 && _portsd.IsReady && _min.IsReady && _max.IsReady ;} } public bool WasJustUpdated(DateTime current) { return Bars.Count > 0 && Bars[0].Time == current - BarPeriod; } } } // close algo }