Overall Statistics |
Total Trades 9522 Average Win 0.06% Average Loss -0.08% Compounding Annual Return 190.724% Drawdown 34.700% Expectancy 0.481 Net Profit 549.569% Sharpe Ratio 0.779 Loss Rate 14% Win Rate 86% Profit-Loss Ratio 0.72 Alpha 1.489 Beta 0.316 Annual Standard Deviation 1.933 Annual Variance 3.735 Information Ratio 0.752 Tracking Error 1.934 Treynor Ratio 4.769 Total Fees $34746.70 |
using System; using System.Collections.Generic; using QuantConnect.Data; using QuantConnect.Data.Market; using System.Linq; using QuantConnect.Interfaces; using QuantConnect.Indicators; using QuantConnect.Securities; using QuantConnect.Orders.Slippage; using QuantConnect.Orders; using QuantConnect.Data.Consolidators; namespace Test { public class TestAlgo : QCAlgorithm { public RollingWindow<decimal> BidPrice = new RollingWindow<decimal>(4); public RollingWindow<decimal> AskPrice = new RollingWindow<decimal>(4); public RollingWindow<decimal> Volume = new RollingWindow<decimal>(4); private OrderTicket EntryOrder { get; set; } private Func<QCAlgorithm, string, decimal, OneCancelsOtherTicketSet> OnOrderFilledEvent { get; set; } private OneCancelsOtherTicketSet ProfitLossOrders { get; set; } private const string Testalgo = Futures.Metals.Palladium ; public Symbol contract = QuantConnect.Symbol.Create(Testalgo, SecurityType.Future, Market.USA); public override void Initialize() { SetStartDate(2018, 01, 01); SetEndDate(DateTime.Now); SetCash(1000000); var contract = AddFuture(Testalgo, Resolution.Minute); contract.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(365)); contract.SetSlippageModel(new CustomSlippageModel(this)); } public override void OnData(Slice slice) { foreach(var chain in slice.FutureChains) { if (chain.Value.Symbol.StartsWith("PA")) { var test = (from futuresContract in chain.Value.OrderBy(x => x.Expiry) where futuresContract.Expiry > Time.Date.AddDays(1) select futuresContract).FirstOrDefault(); AskPrice.Add(test.AskPrice); BidPrice.Add(test.BidPrice); Volume.Add(test.Volume); if (!AskPrice.IsReady || !BidPrice.IsReady || !Volume.IsReady) continue; if (test != null) { if (test.LastPrice != 0) { var _CashLoss = 50000 ; var _valpoint = 5 ; var _minprizefluc = 0.05m ; var _TPLong = 1.0002m ; var _SLLong = 0.8m ; var _TPShort = 1.0002m ; var _SLShort = 0.8m ; var _quantity = (_CashLoss/(_valpoint*(((AskPrice[0]+BidPrice[0])/2)-_SLShort*((AskPrice[0]+BidPrice[0])/2))/_minprizefluc)) ; if (BidPrice[0]>AskPrice[1]) { if (BidPrice[2]>AskPrice[1]) { this.OnOrderFilledEvent = (Testalgo, Symbol, FillPrice) => { return new OneCancelsOtherTicketSet( Testalgo.LimitOrder(test.Symbol, -_quantity, FillPrice * _TPLong, "Profit Long _Target"), Testalgo.StopMarketOrder(test.Symbol, -_quantity, FillPrice * _SLLong, "Stop Long _Loss")); }; this.EntryOrder = MarketOrder(test.Symbol, _quantity, false, "Entry"); }} if (AskPrice[0]<BidPrice[1]) { if (AskPrice[2]<BidPrice[1]) { this.OnOrderFilledEvent = (Testalgo, Symbol, FillPrice) => { return new OneCancelsOtherTicketSet( Testalgo.LimitOrder(test.Symbol, -_quantity, FillPrice * _TPLong, "Profit Short _Target"), Testalgo.StopMarketOrder(test.Symbol, -_quantity, FillPrice * _SLLong, "Stop Short _Loss")); }; this.EntryOrder = MarketOrder(test.Symbol, _quantity, false, "Entry"); }} } } } } } public override void OnOrderEvent(OrderEvent orderEvent) { if (EntryOrder != null) { this.EntryOrder = null; } if (orderEvent.Status == OrderStatus.Filled || orderEvent.Status == OrderStatus.PartiallyFilled) { if (this.OnOrderFilledEvent != null) { this.ProfitLossOrders = OnOrderFilledEvent(this, orderEvent.Symbol, orderEvent.FillPrice); OnOrderFilledEvent = null; } else if (this.ProfitLossOrders != null) { this.ProfitLossOrders.Filled(); this.ProfitLossOrders = null; } } } public class CustomSlippageModel : ISlippageModel { private readonly QCAlgorithm _algorithm; public CustomSlippageModel(QCAlgorithm algorithm) { _algorithm = algorithm; } public decimal GetSlippageApproximation(Security asset, Order order) { // custom slippage math var slippage = asset.Price*0.01m*(decimal) Math.Log10(2*(double) order.AbsoluteQuantity); _algorithm.Log("CustomSlippageModel: " + slippage); return slippage; } } /// <summary> /// Margin call warning event handler. This method is called when Portfolio.MarginRemaining is under 5% of your Portfolio.TotalPortfolioValue /// </summary> public override void OnMarginCallWarning() { // this code gets called when the margin remaining drops below 5% of our total portfolio value, it gives the algorithm // a chance to prevent a margin call from occurring // prevent margin calls by responding to the warning and increasing margin remaining var contractHoldings = Securities["DOW30, SP500"].Holdings.Quantity; var shares = (int)(-contractHoldings * .005m); Error(string.Format("{0} - OnMarginCallWarning(): Liquidating {1} shares of SPY to avoid margin call.", Time, shares)); MarketOrder("DOW30, SP500", shares); } /// <summary> /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm. /// </summary> public bool CanRunLocally { get; } = true; /// <summary> /// This is used by the regression test system to indicate which languages this algorithm is written in. /// </summary> public Language[] Languages { get; } = { Language.CSharp }; } }
namespace QuantConnect { public class OneCancelsOtherTicketSet { public OneCancelsOtherTicketSet(params OrderTicket[] orderTickets) { this.OrderTickets = orderTickets; } private OrderTicket[] OrderTickets { get; set; } public void Filled() { // Cancel all the outstanding tickets. foreach (var orderTicket in this.OrderTickets) { if (orderTicket.Status == OrderStatus.Submitted) { orderTicket.Cancel(); } } } } }