| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0.203 Tracking Error 0.453 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset Portfolio Turnover 0% |
#region imports
using System;
using System.Linq;
using System.Drawing;
using QuantConnect;
using QuantConnect.Brokerages;
using QuantConnect.Algorithm;
using QuantConnect.Indicators;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Data.Market;
using QuantConnect.Securities.CryptoFuture;
#endregion
namespace Nelson.Corey.QC.GS
{
public class Main : QCAlgorithm
{
// private readonly string NL = Environment.NewLine;
private readonly RollingWindow<decimal> _priceWindow = new(Parameters.FlatPriceLength);
private Security _crypto;
private QCMarketWrapper _market;
private ChartManager _chartManager;
private TradeBar _lastBar = null;
private bool _flatPrice = true;
public override void Initialize()
{
SetStartDate(2022, 01, 01);
SetEndDate(2023, 07, 01);
InitBinanceFuture(Parameters.BaseCurrency, Parameters.QuoteCurrency);
InitCharts();
}
private void InitBinanceFuture(string baseCurrency, string quoteCurrency)
{
SetCash("USD", 0);
SetCash(quoteCurrency, 10000);
SetBrokerageModel(BrokerageName.Binance, AccountType.Cash);
DefaultOrderProperties = new BinanceOrderProperties
{
TimeInForce = TimeInForce.GoodTilCanceled,
PostOnly = false,
};
_crypto = AddCryptoFuture(baseCurrency+quoteCurrency, Resolution.Minute);
_crypto.SetMarginModel(new CryptoFutureMarginModel(Parameters.Leverage));
Log($"Trading Binance Future {_crypto} with {_crypto.Leverage} leverage.");
}
private void InitCharts()
{
_chartManager = new ChartManager(this);
_chartManager.AddSecurity(_crypto, Color.LightGray);
}
public override void OnData(Slice data)
{
try
{
var symbol = _crypto.Symbol;
// Sometimes QC can't fill forward, so do it ourselves.
TradeBar bar = data.Bars.TryGetValue(symbol, out TradeBar temp) ? temp : _lastBar;
_lastBar = bar;
UpdateFlatPrice(bar.Close);
if (IsWarmingUp) return;
_chartManager.UpdateCharts();
if (!IsMarketOpen(symbol)) return;
}
catch (Exception e)
{
// NotifyUnknownException(e, "Main.OnData()");
}
}
private void UpdateFlatPrice(decimal price)
{
_priceWindow.Add(price);
if (!_priceWindow.IsReady || !IsMarketOpen(_crypto.Symbol)) return;
var firstPrice = _priceWindow[_priceWindow.Size - 1];
bool flat = _priceWindow.Take(_priceWindow.Size - 1).All(price => price == firstPrice);
if (!_flatPrice && flat)
{
Log($"WARNING: Price has flatlined at {firstPrice} for {_priceWindow.Size} bars.");
}
else if (_flatPrice && !flat)
{
decimal oldPrice = _priceWindow[1];
var percent = (_priceWindow[0] - oldPrice) / oldPrice;
Log($"Price has jumped {percent:P2} to {_priceWindow[0]}.");
}
_flatPrice = flat;
}
public override void OnEndOfAlgorithm()
{
Log($"EndOfAlgo called.");
base.OnEndOfAlgorithm();
}
public override void OnBrokerageDisconnect()
{
try {
Log("Disconnected from Binance brokerage.");
base.OnBrokerageDisconnect();
}
catch (Exception e)
{
// NotifyUnknownException(e, "Main.OnBrokerageDisconnect()");
}
}
// todo: Override more parent methods.
}
}
#region imports
using QuantConnect.Orders;
#endregion
namespace Nelson.Corey.QC.Util
{
public static class Extensions
{
public static bool IsFilled(this OrderTicket ticket)
{
return ticket.Status == OrderStatus.Filled;
}
}
}
#region imports
using System.Collections.Generic;
using System.Drawing;
using QuantConnect;
using QuantConnect.Securities;
#endregion
namespace Nelson.Corey.QC.GS
{
public class ChartManager
{
private readonly Main _algo;
private readonly Chart _indicatorsChart;
private const string FillsSeriesName = "Fills";
private readonly Dictionary<Security, Color> _securities = new();
public ChartManager(Main algo)
{
_algo = algo;
_indicatorsChart = new Chart("Indicators");
_algo.AddChart(_indicatorsChart);
CreateSeries(FillsSeriesName, Color.Lime);
}
private void CreateSeries(string name, in Color color)
{
_indicatorsChart.AddSeries(new Series(name, SeriesType.Line, "$", color));
}
internal void AddSecurity(Security security, in Color color)
{
_securities[security] = color;
_indicatorsChart.AddSeries(new Series(security.Symbol.Value, SeriesType.Line, "$", color));
}
internal void UpdateCharts()
{
#pragma warning disable
if (_algo.Time.Minute % 60 == 0 && _algo.Time.Hour % Parameters.ChartUpdateHours == 0)
#pragma warning restore
{
foreach(var s in _securities.Keys) {
_algo.Plot(_indicatorsChart.Name, s.Symbol.Value, s.Price);
}
}
}
}
}#region imports
using System;
using QuantConnect.Algorithm;
using QuantConnect.Securities;
#endregion
namespace Nelson.Corey.QC.GS
{
internal class QCMarketWrapper
{
private readonly QCAlgorithm _algo;
private readonly Security _security;
private readonly decimal _priceIncrement;
private static void ParseTag(string tag, out string direction, out string posType, out int posId, out string posOrderType)
{
var words = tag.Split(' ', 5);
direction = words[0];
posType = words[1];
posId = Convert.ToInt32(words[2]);
posOrderType = words[3];
}
internal QCMarketWrapper(QCAlgorithm algo, Security security) {
_algo = algo;
_security = security;
_priceIncrement = security.PriceVariationModel.GetMinimumPriceVariation(
new GetMinimumPriceVariationParameters(security, security.Price));
}
internal void Log(string message)
{
_algo.Log(message);
}
internal void Error(string message)
{
_algo.Error($"ERROR: {message}");
}
}
}#region imports
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Drawing;
using QuantConnect;
using QuantConnect.Algorithm.Framework;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Parameters;
using QuantConnect.Benchmarks;
using QuantConnect.Brokerages;
using QuantConnect.Util;
using QuantConnect.Interfaces;
using QuantConnect.Algorithm;
using QuantConnect.Indicators;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Custom;
using QuantConnect.DataSource;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Notifications;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.Slippage;
using QuantConnect.Scheduling;
using QuantConnect.Securities;
using QuantConnect.Securities.Equity;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
using QuantConnect.Securities.Forex;
using QuantConnect.Securities.Crypto;
using QuantConnect.Securities.Interfaces;
using QuantConnect.Storage;
using QuantConnect.Data.Custom.AlphaStreams;
using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion
namespace Nelson.Corey.QC.GS
{
public static class Parameters
{
private const int hour = 60;
// Scalp Strategy
internal const bool EnableScalpPositions = true;
internal const decimal ScalpLots = 2;
internal const int ScalpTakeProfitEmaLength = 60*hour;
// Hinge Strategy
internal const bool EnableHingePositions = true;
internal const bool OpenHingeWhenBreakoutCloses = false;
internal const decimal HingeLots = 2;
public const int HingeFastEmaLength = 6*hour; // used to close Hinges
public const int HingeSlowEmaLength = 12*hour; // used to close Hinges
// Breakout Strategy
internal const bool EnableBreakoutPositions = true; // opens BreakoutLots postion for profit
internal const bool EnableBreakoutNeutralization = true; // neutralize any open positions in the opposite direction
internal const decimal BreakoutLots = 1;
internal const decimal BreakoutStdDevs = 1.9M; // Std Dev's of the Bollingerbands used for opening the breakout
internal const int BreakoutFastEma = 3*hour; // Used for opening and closing the breakout
internal const int BreakoutSlowEma = 9*hour; // Used for closing the breakout
// Indicators
public const int OrangeBBLength = 120*hour;
public const int RedBBLength = 480*hour;
public const decimal BBStdDevs = 2.0M;
// Misc.
public static readonly string BaseCurrency = "BTC";
public static readonly string QuoteCurrency = "BUSD";
public static readonly string NotifyEmails = "corey.nelson+GS3@proton.me;goodservant.trading@gmail.com";
public const decimal LotSize = 0.001M; // BTC
public const decimal Leverage = 10M; // leverage allowed before we start getting Insuffient buying power.
public const int FlatPriceLength = 20; // number of bars to wait before warning about flatline.
public const int ChartUpdateHours = 8; // Update the Indicators chart every n hours.
}
}