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