Overall Statistics |
Total Trades 737 Average Win 0.13% Average Loss -0.08% Compounding Annual Return 2.925% Drawdown 10.900% Expectancy -0.016 Net Profit 1.176% Sharpe Ratio 0.224 Probabilistic Sharpe Ratio 28.928% Loss Rate 63% Win Rate 37% Profit-Loss Ratio 1.65 Alpha 0.039 Beta 0.017 Annual Standard Deviation 0.172 Annual Variance 0.03 Information Ratio 0.164 Tracking Error 0.463 Treynor Ratio 2.211 Total Fees $23582.70 |
using System; using System.Collections.Generic; using System.Linq; using QuantConnect.Data; using QuantConnect.Data.Consolidators; using QuantConnect.Data.Market; namespace QuantConnect { public class BasicTemplateAlgorithm : QCAlgorithm { private OrderTicket EntryOrderUp1 { get; set; } private Func<QCAlgorithm, string, decimal, DateTime, OneCancelsOtherTicketSetUp1> OnOrderFilledEventUp1 { get; set; } private OneCancelsOtherTicketSetUp1 ProfitLossOrdersUp1 { get; set; } public readonly TimeSpan BarPeriod1D = TimeSpan.FromMinutes(240); public readonly int RollingWindowSize = 3; public readonly Dictionary<string, SymbolData1D> Data1D = new Dictionary<string, SymbolData1D>(); decimal UP_SL = 0; decimal UP_TP1 = 0; decimal UP_TP2 = 0; int quantity = 0; int quantity_SL = 0; int quantity_TP1 = 0; int quantity_TP2 = 0; OrderTicket LimitOrder_Symbol_UP_TP1 {get; set;} OrderTicket StopMarket_Symbol_UP_SL1 {get; set;} OrderTicket LimitOrder_Symbol_UP_TP2 {get; set;} OrderTicket StopMarket_Symbol_UP_SL2 {get; set;} public readonly IReadOnlyList<string> ForexSymbols = new List<string> { "EURUSD", "USDJPY", "EURGBP", "EURNZD", "EURAUD", "EURCHF", "USDCAD", "USDCHF", "AUDUSD", "NZDUSD", "GBPJPY", "EURJPY", "GBPAUD", "AUDJPY", "EURCAD", "AUDCAD", "CADJPY", }; public override void Initialize() { SetStartDate(2020,01, 1); SetEndDate(DateTime.Now.Date.AddDays(-1)); SetCash(2500000); SetBrokerageModel(BrokerageName.FxcmBrokerage); foreach (var symbol in ForexSymbols) { var forex = AddForex(symbol); Data1D.Add(symbol, new SymbolData1D(forex.Symbol, BarPeriod1D, RollingWindowSize)); } foreach (var kvp in Data1D) { var symbolData1D = kvp.Value; var consolidator1D = symbolData1D.Symbol.SecurityType == SecurityType.Equity ? (IDataConsolidator)new TradeBarConsolidator(BarPeriod1D) : (IDataConsolidator)new QuoteBarConsolidator(BarPeriod1D); consolidator1D.DataConsolidated += (sender, baseData) => { var bar = (IBaseDataBar)baseData; symbolData1D.Bars.Add(bar); }; SubscriptionManager.AddConsolidator(symbolData1D.Symbol, consolidator1D); } } public void OnData(Slice slice) { foreach (var symbolData1D in Data1D.Values) { if (symbolData1D.IsReady && symbolData1D.WasJustUpdated(Time)) { bool BarPrecRed = symbolData1D.Bars[1].Open - symbolData1D.Bars[1].Close > 0 ; bool BarPrecGreen = symbolData1D.Bars[1].Close - symbolData1D.Bars[1].Open > 0 ; bool BarCurrentGreen = symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Open > 0 ; bool Signal_Condition_Up = BarPrecRed && BarCurrentGreen && ((symbolData1D.Bars[1].Open - symbolData1D.Bars[1].Close) > symbolData1D.Bars[1].Open * 0.001m) && ((symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Open) * 3 < (symbolData1D.Bars[1].Open - symbolData1D.Bars[1].Close)) ; UP_SL = (symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Low) ; UP_TP1 = (symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Low) ; UP_TP2 = ((symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Low) * 2) ; quantity = ((int)Math.Floor(Portfolio.Cash) + (int)Math.Floor(Portfolio.TotalProfit)) / 2; quantity_SL = quantity; quantity_TP1 = (int)Math.Floor(quantity * 0.5m); quantity_TP2 = (int)Math.Floor(quantity_TP1 * 1m); if (Signal_Condition_Up && EntryOrderUp1 == null) { this.OnOrderFilledEventUp1 = (algo1, symbol, filledPrice, dt) => { return new OneCancelsOtherTicketSetUp1( LimitOrder_Symbol_UP_TP1 = algo1.LimitOrder(symbolData1D.Symbol, -quantity_TP1, filledPrice + UP_TP1, "TP1"), StopMarket_Symbol_UP_SL1 = algo1.StopMarketOrder(symbolData1D.Symbol, -quantity_TP1, filledPrice - UP_SL, "SL1"), LimitOrder_Symbol_UP_TP2 = algo1.LimitOrder(symbolData1D.Symbol, -quantity_TP2, filledPrice + UP_TP2, "TP2"), StopMarket_Symbol_UP_SL2 = algo1.StopMarketOrder(symbolData1D.Symbol, -quantity_TP2, filledPrice - UP_SL, "SL2")); }; this.EntryOrderUp1 = MarketOrder(symbolData1D.Symbol, quantity_TP1, false, "Entry_TP1 : " + Time); this.EntryOrderUp1 = MarketOrder(symbolData1D.Symbol, quantity_TP2, false, "Entry_TP2 : " + Time); } } } } public override void OnOrderEvent(OrderEvent orderEvent) { var order = Transactions.GetOrderById(orderEvent.OrderId); if (EntryOrderUp1 != null) { this.EntryOrderUp1 = null; } if (orderEvent.Status == OrderStatus.Filled || orderEvent.Status == OrderStatus.PartiallyFilled) { if (this.OnOrderFilledEventUp1 != null) { this.ProfitLossOrdersUp1 = OnOrderFilledEventUp1(this, orderEvent.Symbol, orderEvent.FillPrice, orderEvent.UtcTime); OnOrderFilledEventUp1 = null; } else if (this.ProfitLossOrdersUp1 != null) { if (order.Type == OrderType.StopMarket) { this.ProfitLossOrdersUp1.Filled(); this.ProfitLossOrdersUp1 = null; } } } if (orderEvent.Status == OrderStatus.Filled && this.ProfitLossOrdersUp1 != null) { if ((order.Tag.Equals("TP1"))) { StopMarket_Symbol_UP_SL1.Cancel(); } if ((order.Tag.Equals("TP2"))) { StopMarket_Symbol_UP_SL2.Cancel(); ////Don't forget to put this ProfitLossOrdersUp1 reset to null here, in the last level of Take-Profit. this.ProfitLossOrdersUp1 = null; } } } } public class SymbolData1D { public readonly Symbol Symbol; public readonly RollingWindow<IBaseDataBar> Bars; public readonly TimeSpan BarPeriod1D; public SymbolData1D(Symbol symbol, TimeSpan barPeriod1D, int windowSize) { Symbol = symbol; BarPeriod1D = barPeriod1D; Bars = new RollingWindow<IBaseDataBar>(windowSize); } public bool IsReady { get { return Bars.IsReady;} } public bool WasJustUpdated(DateTime current) { return Bars.Count > 0 && Bars[0].Time == current - BarPeriod1D; } } }
namespace QuantConnect { public class OneCancelsOtherTicketSetUp1 { public OneCancelsOtherTicketSetUp1(params OrderTicket[] orderTicketsUp1) { this.OrderTicketsUp1 = orderTicketsUp1; } private OrderTicket[] OrderTicketsUp1 { get; set; } public void Filled() { // Cancel all the outstanding tickets. foreach (var orderTicket in this.OrderTicketsUp1) { if (orderTicket.Status == OrderStatus.Submitted) { orderTicket.Cancel(); } } } } }