| Overall Statistics |
|
Total Trades 2009 Average Win 2.14% Average Loss -0.75% Compounding Annual Return -10.108% Drawdown 99.700% Expectancy -0.011 Net Profit -21.954% Sharpe Ratio 0.095 Probabilistic Sharpe Ratio 4.704% Loss Rate 74% Win Rate 26% Profit-Loss Ratio 2.84 Alpha 0.054 Beta -0.055 Annual Standard Deviation 0.506 Annual Variance 0.256 Information Ratio -0.099 Tracking Error 0.52 Treynor Ratio -0.878 Total Fees $23723.94 |
using System;
using System.Collections.Generic;
using System.Globalization;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
namespace QuantConnect.Algorithm.CSharp
{
public class MultiSymboleEMACrossFramework: QCAlgorithm
{
private const Resolution resolution = Resolution.Hour;
public int fastPeriod = 12;
public int slowPeriod = 26;
// list of symbols (universe)
/* private List<string> CryptoSymbols = new List<string>
{
"BTCUSD",
"ETHUSD",
"LTCUSD"
};
*/
private Dictionary<string, string> CryptoSymbols = new Dictionary<string, string>()
{
{"BTCUSD", "BTC"},
{"ETHUSD", "ETH"},
{"LTCUSD", "LTC"}
};
public Dictionary<string, string> CryptoSymbols1 = new Dictionary<string, string>();
public override void Initialize()
{
SetStartDate(2017, 9, 1); //Set Start Date
//SetEndDate(2017, 1, 28); //Set End Date
SetEndDate(2019, 12, 28); //Set End Date
SetCash(10000); //Set Strategy Cash
// AddEquity("SPY", Resolution.Minute);
AddAlpha(new EmaCrossAlphaModel(fastPeriod, slowPeriod, resolution));
SetExecution(new ImmediateExecutionModel());
//SetPortfolioConstruction(new NullPortfolioConstructionModel());
// SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel(resolution));
SimpleEqualWeightPortfolioConstructionModel portfolioModel = new SimpleEqualWeightPortfolioConstructionModel();
SetPortfolioConstruction(portfolioModel);
portfolioModel.SetSymbols(CryptoSymbols);
UniverseSettings.Resolution = resolution;
var symbols = new Symbol[CryptoSymbols.Count];
var baseSymbols = new string[CryptoSymbols.Count];
int i = 0;
foreach(var symbol in CryptoSymbols)
{
symbols[i] = QuantConnect.Symbol.Create(symbol.Key, SecurityType.Crypto, Market.GDAX);
CryptoSymbols1.Add(symbol.Key,symbol.Value);
i++;
}
SetUniverseSelection( new ManualUniverseSelectionModel(symbols) );
//SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash);
foreach (var security in ActiveSecurities)
{
Log($"Securities {security.Value.ToString()}");
}
}
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// Slice object keyed by symbol containing the stock data
public override void OnData(Slice data)
{
// if (!Portfolio.Invested)
// {
// SetHoldings(_spy, 1);
// Debug("Purchased Stock");
//}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
foreach (var security in changes.AddedSecurities)
{
Log($"Securities {security.ToString()}");
security.FeeModel = new GDAXFeeModel();
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
var order = Transactions.GetOrderById(orderEvent.OrderId);
// if (orderEvent.Status == OrderStatus.Submitted)
// {
// Log(
// $" Order {orderEvent.Status} [{orderEvent.Symbol}] {order.Type} {order.Direction}" +
// $" Quantity {order.Quantity} Current Price {Portfolio.Securities[orderEvent.Symbol].Close}" +
// $" Cash {Portfolio.CashBook["USD"].Amount}"
// );
// }
if (orderEvent.Status == OrderStatus.Filled)
{
if (order.Direction == OrderDirection.Buy)
{
Log(
$" Order {orderEvent.Status} [{orderEvent.Symbol}] {order.Type} {order.Direction}" +
$" Quantity {orderEvent.FillQuantity} Price {orderEvent.FillPrice} Commission {orderEvent.OrderFee}" +
$" Cash {Portfolio.CashBook["USD"].Amount}" +
$" Equity {Portfolio.TotalPortfolioValue}"
);
}
else
{
var holdings = Portfolio.Securities[orderEvent.Symbol].Holdings;
Log(
$" Order {orderEvent.Status} [{orderEvent.Symbol}] {order.Type} {order.Direction}" +
$" Quantity {orderEvent.FillQuantity} Price {orderEvent.FillPrice} Commission {orderEvent.OrderFee}" +
// $" CostBase {holdings.AveragePrice}" +
$" P&L {holdings.LastTradeProfit}" +
$" Cash {Portfolio.CashBook["USD"].Amount}" +
$" Equity {Portfolio.TotalPortfolioValue}"
);
}
}
}
/// <summary>
/// Portfolio construction model that equally distribute cash among non-holding securities.
/// Long only. Go flat if there is Down signal
/// </summary>
class SimpleEqualWeightPortfolioConstructionModel : PortfolioConstructionModel
{
Dictionary<string,string> CryptoSymbols = new Dictionary<string, string>();
public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights)
{
foreach (var insight in insights)
{
/*algorithm.Log(
$"Insight Symbol {insight.Symbol}" +
//$" CashBook {algorithm.Portfolio.CashBook.ToString()}" +
$" Price {algorithm.Portfolio.Securities[insight.Symbol].Close}" +
$" Amount {algorithm.Portfolio.CashBook[CryptoSymbols[insight.Symbol]].Amount}"
// $" direction {insight.Direction} " +
$" Type {insight.Type} Model {insight.SourceModel}");
);*/
if (algorithm.Portfolio.CashBook[CryptoSymbols[insight.Symbol]].Amount != 0 &&
(int) insight.Direction == -1)
{
yield return new PortfolioTarget(insight.Symbol, 0);
}
else if (algorithm.Portfolio.CashBook[CryptoSymbols[insight.Symbol]].Amount == 0 &&
(int) insight.Direction == 1)
{
var cash = algorithm.Portfolio.CashBook["USD"].Amount;
int holdings = 0;
foreach (var x in CryptoSymbols)
{
if (algorithm.Portfolio.CashBook[x.Value].Amount > 0)
{
holdings++;
}
}
int openSlots = CryptoSymbols.Count - holdings;
decimal targetQuant = Math.Round(
cash / openSlots / algorithm.Portfolio.Securities[insight.Symbol].Close * 0.95m,
2
);
yield return new PortfolioTarget(insight.Symbol, targetQuant);
//yield return new PortfolioTarget(insight.Symbol, 1.5m);
}
}
}
public void SetSymbols(Dictionary<string, string> cryptoSymbols)
{
CryptoSymbols = cryptoSymbols;
}
}
}
}