Overall Statistics |
Total Trades 128 Average Win 7.53% Average Loss -0.51% Compounding Annual Return 1.704% Drawdown 26.300% Expectancy 1.647 Net Profit 14.330% Sharpe Ratio 0.185 Probabilistic Sharpe Ratio 0.311% Loss Rate 83% Win Rate 17% Profit-Loss Ratio 14.88 Alpha -0.013 Beta 0.325 Annual Standard Deviation 0.082 Annual Variance 0.007 Information Ratio -0.59 Tracking Error 0.123 Treynor Ratio 0.047 Total Fees $128.59 Estimated Strategy Capacity $4900000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X |
using Accord; using Accord.Math; using QLNet; using QuantConnect.Algorithm.CSharp.Benchmarks; using QuantConnect.Algorithm.Framework.Portfolio; using QuantConnect.Brokerages; using QuantConnect.Data; using QuantConnect.Indicators; using QuantConnect.Orders; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Security.Cryptography; using System.Threading; using System.Transactions; using VerifyRsi; namespace QuantConnect.Algorithm.CSharp { public class Verifyrsi : QCAlgorithm { private Symbol _symbol; private RelativeStrengthIndex _rsi; private decimal OverBoughtLevel = 80m; private decimal OverSoldLevel = 25m; private RollingWindow<decimal> _rsiLastValue; private const decimal Cash = 100000m; private const decimal PercentageOfAssetsPerOrder = 0.02m; // market-order with stop-loss private ConcurrentDictionary<OrderTicket, OrderTicket> _orders; private Chart _rsiChart; public override void Initialize() { SetStartDate(2015, 1, 1); // Set Start Date SetEndDate(2022, 12, 2); // Set End Date SetCash(Cash); // Set Strategy Cash _symbol = AddEquity("SPY", Resolution.Hour, dataNormalizationMode: DataNormalizationMode.Raw).Symbol; EnableAutomaticIndicatorWarmUp = true; _rsi = RSI(_symbol, 14, MovingAverageType.Wilders, Resolution.Daily); _rsiLastValue = new RollingWindow<decimal>(2); _orders = new ConcurrentDictionary<OrderTicket, OrderTicket>(new OrderTicketEqualityComparer()); SetBenchmark("SPY"); SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin); // plotting _rsiChart = new Chart("RSI"); _rsiChart.AddSeries(new Series("RSI", SeriesType.Line, "", Color.Green)); AddChart(_rsiChart); } /// 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 (!data.Bars.ContainsKey(_symbol)) return; if (!_rsi.IsReady) return; if (!_rsiLastValue.IsReady) return; if (IsSell()) { if (Portfolio[_symbol].IsLong) { Debug($"It's long. Liquidating. Profit: {Portfolio[_symbol].Profit}"); Liquidate(_symbol); } Trade(false); } if (IsBuy()) { if (Portfolio[_symbol].IsShort) { Debug($"It's short. Liquidating. Profit: {Portfolio[_symbol].Profit}"); Liquidate(_symbol); } Trade(true); } } public void Trade(bool isBuy) { var stocksCount = PortfolioTarget.Percent(this, _symbol, PercentageOfAssetsPerOrder).Quantity; if (!isBuy) { stocksCount = -stocksCount; } var ticket = MarketOrder(_symbol, stocksCount); _orders.TryAdd(ticket, null); } public override void OnOrderEvent(OrderEvent orderEvent) { if (orderEvent.Status == OrderStatus.Canceled) { Debug($"OrderEvent with id {orderEvent.Id} was cancelled and orderId {orderEvent.OrderId}"); // the main order was cancelled var cancelledOrder = _orders.FirstOrDefault(c => c.Key.OrderId == orderEvent.OrderId); if (cancelledOrder.Value != null) // if there is stop-loss { Debug($"Order wan't executed"); cancelledOrder.Value.Cancel(); _orders.TryRemove(cancelledOrder); } // the stop-loss order was cancelled var cancelledStopLossOrder = _orders.FirstOrDefault(c => c.Value?.OrderId == orderEvent.OrderId); if (_orders.TryRemove(cancelledStopLossOrder.Key, out var stopLossCancelledOrder)) { Debug("Stop loss order was cancelled"); stopLossCancelledOrder.Cancel(); } } if (orderEvent.Status == OrderStatus.Filled) { var filledOrder = _orders.FirstOrDefault(c => c.Key.OrderId == orderEvent.OrderId); if (!filledOrder.Equals(default(KeyValuePair<OrderTicket, OrderTicket>))) { var ticket = filledOrder.Key; var fillPrice = ticket.AverageFillPrice; var direction = ticket.Quantity > 0 ? Position.Type.Long : Position.Type.Short; decimal stopPrice = direction == Position.Type.Long ? ticket.AverageFillPrice - ticket.AverageFillPrice * 0.02m : ticket.AverageFillPrice + ticket.AverageFillPrice * 0.02m; var stocksCount = -ticket.Quantity; var stopLossTicket = StopMarketOrder(_symbol, stocksCount, stopPrice); _orders[filledOrder.Key] = stopLossTicket; Debug($"{direction}. Fill price {fillPrice}. StopLoss price {stopPrice}"); } var executedStopLossOrder = _orders.FirstOrDefault(c => c.Value?.OrderId == orderEvent.OrderId); if (!executedStopLossOrder.Equals(default(KeyValuePair<OrderTicket, OrderTicket>)) && _orders.TryRemove(executedStopLossOrder.Key, out var stopLossExecutedOrder)) { var initialOrder = executedStopLossOrder.Key; Debug($"StopLossExecuted. Initial order {initialOrder.OrderId} with filled price {initialOrder.AverageFillPrice} was closed by {stopLossExecutedOrder.AverageFillPrice} with orderId {stopLossExecutedOrder.OrderId}"); } } base.OnOrderEvent(orderEvent); } public override void OnEndOfDay(Symbol symbol) { if (!_rsi.IsReady) return; var rsiCurrentValue = _rsi.Current.Value; _rsiLastValue.Add(rsiCurrentValue); Plot("RSI", "RSI", _rsi.Current.Value); } private bool IsBuy() { var rsiCurrentValue = _rsi.Current.Value; var rsiLastValue = _rsiLastValue[1]; var isBuy = rsiLastValue <= OverSoldLevel && rsiCurrentValue > OverSoldLevel; if (isBuy) { Debug($"RSI last: {rsiLastValue} RSI current: {rsiCurrentValue}"); return true; } return false; } private bool IsSell() { var rsiCurrentValue = _rsi.Current.Value; var rsiLastValue = _rsiLastValue[1]; var isSell = rsiLastValue >= OverBoughtLevel && rsiCurrentValue < OverBoughtLevel; if (isSell) { Debug($"RSI last: {rsiLastValue} RSI current: {rsiCurrentValue}"); return true; } return false; } } }
using QuantConnect.Orders; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; namespace VerifyRsi { public sealed class OrderTicketEqualityComparer : IEqualityComparer<OrderTicket> { public bool Equals(OrderTicket x, OrderTicket y) { return x.OrderId == y.OrderId; } public int GetHashCode([DisallowNull] OrderTicket obj) { return obj.OrderId; } } }