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.
    }
}