| 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();
}
}
}
}
}