Overall Statistics |
Total Trades 157 Average Win 3.88% Average Loss -0.98% Compounding Annual Return 4.423% Drawdown 17.400% Expectancy 0.774 Net Profit 72.687% Sharpe Ratio 0.526 Loss Rate 64% Win Rate 36% Profit-Loss Ratio 3.94 Alpha 0.022 Beta 0.242 Annual Standard Deviation 0.09 Annual Variance 0.008 Information Ratio -0.357 Tracking Error 0.165 Treynor Ratio 0.196 Total Fees $173.73 |
using System.Collections.Concurrent; namespace QuantConnect { public class KAMA : QCAlgorithm { string tradeSymbol = "SPY"; //Data Required List<string> _symbols = new List<string>() { "SPY" }; RollingWindow<TradeBar> _window = new RollingWindow<TradeBar>(110); private RollingWindow<decimal> _amaW = new RollingWindow<decimal>(5); TradeBars _bars = new TradeBars(); //global vars decimal _delta; decimal _noise; decimal _er; decimal _c; decimal _ama; decimal _prevama; decimal _slowsc; decimal _fastsc; decimal _s; StandardDeviation _sd; //Sum _sum; //kama parameters int _period = 100; int _fast = 2; int _slow = 30; int _filterPeriod = 100; //double _filterIndex = 0.1; // used for sl*ATR //Initialize the data and resolution you require for your strategy: public override void Initialize() { //Start and End Date range for the backtest: SetStartDate(2003, 1, 1); //SetEndDate(2015, 6, 5); SetEndDate(DateTime.Now.AddDays(-1)); //Cash allocation SetCash(25000); //Add as many securities as you like. All the data will be passed into the event handler: foreach (var symbol in _symbols) { AddSecurity(SecurityType.Equity, symbol, Resolution.Daily); Securities[symbol].SetDataNormalizationMode(DataNormalizationMode.Raw); //Securities[symbol].TransactionModel = new CustomTransactionModel(); } //Add as many securities as you like. All the data will be passed into the event handler: /*foreach (var symbol in _symbols) { AddSecurity(SecurityType.Forex, symbol, Resolution.Daily); //Securities[symbol].SetLeverage(50m); //Securities[symbol].TransactionModel = new CustomForexTransactionModel(); }*/ //_symbols.AddRange(_EqSymbols); //updated inside OnData //_sum = new Sum(_period); _sd = new StandardDeviation(_filterPeriod); } //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; //foreach(var symbol in _symbols) //{ try { _window.Add(_bars[tradeSymbol]); if(!_window.IsReady) return; _er = 1m; _delta = Math.Abs(_window[0].Close - _window[_period].Close); _noise = Math.Abs(_window[0].Close - _window[1].Close); _s = 0; for (int i=_period; i >= 0; i--) { _s += Math.Abs(_window[i].Close - _window[i+1].Close); } if(_s != 0) { _er = _delta/_s; } _slowsc = 2m /(_slow+1); _fastsc = 2m /(_fast+1); _c = (_er*(_fastsc - _slowsc) + _slowsc) * (_er*(_fastsc - _slowsc) + _slowsc); //original / optimised kama if(_prevama != 0) { _ama = _prevama + _c*(_window[0].Close - _prevama); } else { _ama = _window[0].Close; } _amaW.Add(_ama); if(!_amaW.IsReady) return; TradeBar bar; if (_bars.TryGetValue(tradeSymbol, out bar)) { _sd.Update(bar.Time, (_amaW[0]-_amaW[1])); } //indies Plot("KAMA", "ama window", _ama); Plot("KAMA StDev", "ama window", _sd); //exits if(Portfolio.HoldStock) { //10% stop loss of everything vavailable if (Securities[tradeSymbol].Holdings.UnrealizedProfit < -Portfolio.TotalPortfolioValue*0.1m) { Liquidate(tradeSymbol); } if(Portfolio[tradeSymbol].IsLong)// && _amaW[0] < _amaW[1] && _amaW[1] > _amaW[2]) { //decimal max = _amaW[1] - _amaW[0]; if(_amaW[0] < _amaW[1])// && max < _sd*(decimal)_filterIndex) { Liquidate(tradeSymbol); } } } //entries if(_prevama != 0) { if(!Portfolio.HoldStock)// && _amaW[0] > _amaW[1] && _amaW[1] < _amaW[2]) { //decimal min = _amaW[0] - _amaW[1]; if(_amaW[0] > _amaW[1])// && min > _sd*(decimal)_filterIndex) { SetHoldings(tradeSymbol,0.9); } } } _prevama = _ama; } catch(Exception err) { Log("ERROR. "+err.Message); } } //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; } } } // end of algo } //end of namesace
namespace QuantConnect.Securities.Forex { /// <summary> /// Forex Transaction Model Class: Specific transaction fill models for FOREX orders /// </summary> /// <seealso cref="SecurityTransactionModel"/> /// <seealso cref="ISecurityTransactionModel"/> public class CustomForexTransactionModel : SecurityTransactionModel { private readonly decimal _commissionRate; private readonly decimal _minimumOrderFee; /// <summary> /// Initialise the transaction model class /// </summary> public CustomForexTransactionModel(decimal monthlyTradeAmountInUSDollars = 0) { /* Interactive Brokers Forex Commisions as of 2015.04.15 Monthly Trade Amount Commissions Minimum per Order <=USD 1,000,000,000 0.20basis point * Trade Value USD 2.00 USD 1,000,000,001 - 2,000,000,000 0.15basis point * Trade Value USD 1.50 USD 2,000,000,001 - 5,000,000,000 0.10basis point * Trade Value USD 1.25 >USD 5,000,000,000 0.08basis point * Trade Value USD 1.00 * */ const decimal bp = 0.0001m; if (monthlyTradeAmountInUSDollars <= 1000000000) // 1 billion { _commissionRate = 0.20m*bp; _minimumOrderFee = 2.00m; } else if (monthlyTradeAmountInUSDollars <= 2000000000) // 2 billion { _commissionRate = 0.15m*bp; _minimumOrderFee = 1.50m; } else if (monthlyTradeAmountInUSDollars <= 5000000000) // 5 billion { _commissionRate = 0.20m*bp; _minimumOrderFee = 1.25m; } else { _commissionRate = 0.20m*bp; _minimumOrderFee = 1.00m; } } /// <summary> /// Get the slippage approximation for this order /// </summary> /// <returns>Decimal value of the slippage approximation</returns> /// <seealso cref="Order"/> public override decimal GetSlippageApproximation(Security security, Order order) { //Return 0 by default decimal slippage = 0.0002m; //For FOREX, the slippage is the Bid/Ask Spread for Tick, and an approximation for the switch (security.Resolution) { case Resolution.Minute: case Resolution.Second: //Get the last data packet: //Assume slippage is 1/10,000th of the price slippage = security.GetLastData().Value*0.0002m; break; case Resolution.Tick: var lastTick = (Tick) security.GetLastData(); switch (order.Direction) { case OrderDirection.Buy: //We're buying, assume slip to Asking Price. slippage = Math.Abs(order.Price - lastTick.AskPrice); break; case OrderDirection.Sell: //We're selling, assume slip to the bid price. slippage = Math.Abs(order.Price - lastTick.BidPrice); break; } break; } return slippage; } /// <summary> /// Get the fees from this order /// </summary> /// <param name="quantity">Quantity of purchase</param> /// <param name="price">Price of the currency</param> /// <remarks> /// FXCM now uses a flat fee per trade instead of a spread model. This spread model is /// out of date but the data has the spread built into historical data. >> New data source needed. /// </remarks> /// <returns>Decimal value of the order fee</returns> public override decimal GetOrderFee(decimal quantity, decimal price) { var fee = _commissionRate*quantity*price; return Math.Max(_minimumOrderFee, fee); } /// <summary> /// Default implementation returns 0 for fees. /// </summary> /// <param name="security">The security matching the order</param> /// <param name="order">The order to compute fees for</param> /// <returns>The cost of the order in units of the account currency</returns> public override decimal GetOrderFee(Security security, Order order) { var forex = (Forex) security; // get the total order value in the account currency var price = order.Status.IsFill() ? order.Price : security.Price; var totalOrderValue = order.GetValue(price)*forex.QuoteCurrency.ConversionRate; var fee = _commissionRate*totalOrderValue; return Math.Max(_minimumOrderFee, fee); } } }
namespace QuantConnect.Securities.Forex { /// <summary> /// Forex Transaction Model Class: Specific transaction fill models for FOREX orders /// </summary> /// <seealso cref="SecurityTransactionModel"/> /// <seealso cref="ISecurityTransactionModel"/> public class CustomTransactionModel : SecurityTransactionModel { private readonly decimal _commissionRate; private readonly decimal _minimumOrderFee; /// <summary> /// Initialise the transaction model class /// </summary> public CustomTransactionModel(decimal monthlyTradeAmountInUSDollars = 0) { /* Interactive Brokers Forex Commisions as of 2015.04.15 Monthly Trade Amount Commissions Minimum per Order <=USD 1,000,000,000 0.20basis point * Trade Value USD 2.00 USD 1,000,000,001 - 2,000,000,000 0.15basis point * Trade Value USD 1.50 USD 2,000,000,001 - 5,000,000,000 0.10basis point * Trade Value USD 1.25 >USD 5,000,000,000 0.08basis point * Trade Value USD 1.00 * */ const decimal bp = 0.01m; if (monthlyTradeAmountInUSDollars <= 1000000000) // 1 billion { _commissionRate = 0.20m*bp; _minimumOrderFee = 2.00m; } else if (monthlyTradeAmountInUSDollars <= 2000000000) // 2 billion { _commissionRate = 0.15m*bp; _minimumOrderFee = 1.50m; } else if (monthlyTradeAmountInUSDollars <= 5000000000) // 5 billion { _commissionRate = 0.20m*bp; _minimumOrderFee = 1.25m; } else { _commissionRate = 0.20m*bp; _minimumOrderFee = 1.00m; } } /// <summary> /// Get the slippage approximation for this order /// </summary> /// <returns>Decimal value of the slippage approximation</returns> /// <seealso cref="Order"/> public override decimal GetSlippageApproximation(Security security, Order order) { //Return 0 by default decimal slippage = 0.05m; //For FOREX, the slippage is the Bid/Ask Spread for Tick, and an approximation for the switch (security.Resolution) { case Resolution.Minute: case Resolution.Second: //Get the last data packet: //Assume slippage is 1/10,000th of the price slippage = security.GetLastData().Value*0.0002m; break; case Resolution.Tick: var lastTick = (Tick) security.GetLastData(); switch (order.Direction) { case OrderDirection.Buy: //We're buying, assume slip to Asking Price. slippage = Math.Abs(order.Price - lastTick.AskPrice); break; case OrderDirection.Sell: //We're selling, assume slip to the bid price. slippage = Math.Abs(order.Price - lastTick.BidPrice); break; } break; } return slippage; } /// <summary> /// Get the fees from this order /// </summary> /// <param name="quantity">Quantity of purchase</param> /// <param name="price">Price of the currency</param> /// <remarks> /// FXCM now uses a flat fee per trade instead of a spread model. This spread model is /// out of date but the data has the spread built into historical data. >> New data source needed. /// </remarks> /// <returns>Decimal value of the order fee</returns> public override decimal GetOrderFee(decimal quantity, decimal price) { var fee = _commissionRate*quantity*price; return Math.Max(_minimumOrderFee, fee); } /// <summary> /// Default implementation returns 0 for fees. /// </summary> /// <param name="security">The security matching the order</param> /// <param name="order">The order to compute fees for</param> /// <returns>The cost of the order in units of the account currency</returns> public override decimal GetOrderFee(Security security, Order order) { var forex = (Forex) security; // get the total order value in the account currency var price = order.Status.IsFill() ? order.Price : security.Price; var totalOrderValue = order.GetValue(price)*forex.QuoteCurrency.ConversionRate; var fee = _commissionRate*totalOrderValue; return Math.Max(_minimumOrderFee, fee); } } }
namespace QuantConnect { /* * TimeSpanConsolidator Helper Routine: Assemble generic timespan bar lengths: e.g. 10 minutes: * * 1. Setup the new Consolidator class with the timespan period: * var _consolidator = new Consolidator(TimeSpan.FromMinutes(10)); * * 2. Add in the data with the update routine. It will return true when bar ready * if (_consolidator.Update(data["MSFT"])) { UseBar } */ public class Consolidator { private TradeBar _resultBar; private TradeBar _workingBar; private DateTime _start; private TimeSpan _period; //Result: public TradeBar Bar { get { return _resultBar; } } //Constructor: Set the period we'd like to scan public Consolidator(TimeSpan span) { this._period = span; this._resultBar = new TradeBar(); this._workingBar = new TradeBar(new DateTime(), "", Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0); } //Submit this bar, return true if we've started a new one. public bool Update(TradeBar newBar) { //Intialize: if (_start == new DateTime()) { _start = newBar.Time; } //While we're less than end date, keep adding to this bar: if (newBar.Time < (_start + _period)) { //Building bar: AddToBar(newBar); return false; } else { //Completed bar: start new one: _resultBar = _workingBar; //Create a new bar: _workingBar = new TradeBar(newBar.Time, newBar.Symbol, Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0); //Start of this bar: _start = newBar.Time; AddToBar(newBar); return true; } } //Add to a tradebar private void AddToBar(TradeBar newBar) { //Add this data to working bar: if (_workingBar.Time == new DateTime()) _workingBar.Time = newBar.Time; if (_workingBar.Symbol == "") _workingBar.Symbol = newBar.Symbol; if (_workingBar.Open == Decimal.Zero) _workingBar.Open = newBar.Open; if (newBar.High > _workingBar.High) _workingBar.High = newBar.High; if (newBar.Low < _workingBar.Low) _workingBar.Low = newBar.Low; _workingBar.Close = newBar.Close; _workingBar.Volume = newBar.Volume; } } }