Overall Statistics |
Total Trades 139 Average Win 1.69% Average Loss -1.85% Compounding Annual Return 6.300% Drawdown 53.900% Expectancy 0.276 Net Profit 84.318% Sharpe Ratio 0.415 Loss Rate 33% Win Rate 67% Profit-Loss Ratio 0.91 Alpha 0.081 Beta -0.069 Annual Standard Deviation 0.191 Annual Variance 0.037 Information Ratio 0.216 Tracking Error 0.301 Treynor Ratio -1.158 Total Fees $249.58 |
using System; using QuantConnect.Orders; using QuantConnect.Algorithm; using QuantConnect.Indicators; namespace QuantConnect.RsiMovingAverage { public partial class RsiMovingAverageAlgorithm { bool IsExitSignal(decimal currentPrice) { if (!rsi.IsReady || currentOrder == null || !currentOrder.Status.IsFill()) { return false; } var elapsedTime = Time - purchaseDate; var isPastHoldPeriod = elapsedTime >= holdPeriod; var marketInversion = isShortPosition ? IsLongSignal() : IsShortSignal(); return marketInversion;// || isPastHoldPeriod; } bool IsLongSignal() { return IsUptrend() && IsOverSold(); } bool IsShortSignal() { return IsDowntrend() && IsOverBought(); } bool IsDowntrend() { if (!shortMovingAverage.IsReady || !longMovingAverage.IsReady) { return false; } return shortMovingAverage < longMovingAverage; } bool IsOverBought() { if (!rsi.IsReady) { return false; } return rsi > 92.5m; } bool IsUptrend() { if (!shortMovingAverage.IsReady || !longMovingAverage.IsReady) { return false; } return shortMovingAverage > longMovingAverage; } bool IsOverSold() { if (!rsi.IsReady) { return false; } return rsi < 7.5m; } } }
using System; using QuantConnect.Orders; namespace QuantConnect.RsiMovingAverage { public partial class RsiMovingAverageAlgorithm { int GetPositionSize(decimal currentPrice) { // Fixed Fractional Position Sizing // N = M * R / | p_0 - p_1 | = M * R / S_i var S_i = 0.02m * currentPrice; var N = Portfolio.Cash * 0.02m / S_i; return (int)Math.Floor(N); } void EnterLong(decimal currentPrice) { int quantity = GetPositionSize(currentPrice); currentOrder = Buy(symbol, quantity); profitTarget = LimitOrder(symbol, -quantity, currentPrice * 1.02m); stopLoss = StopMarketOrder(symbol, -quantity, currentPrice * 0.98m); highPrice = lowPrice = currentPrice; isShortPosition = false; purchaseDate = Time; } void EnterShort(decimal currentPrice) { int quantity = GetPositionSize(currentPrice); currentOrder = Sell(symbol, quantity); profitTarget = LimitOrder(symbol, quantity, currentPrice * 0.98m); stopLoss = StopMarketOrder(symbol, quantity, currentPrice * 1.02m); highPrice = lowPrice = currentPrice; isShortPosition = true; purchaseDate = Time; } void ExitMarket() { var quantity = Portfolio[symbol].Quantity; if (profitTarget != null) { profitTarget.Cancel(); } if (stopLoss != null) { stopLoss.Cancel(); } if (isShortPosition) { currentOrder = Buy(symbol, quantity); } else { currentOrder = Sell(symbol, quantity); } } void UpdateStopLoss(decimal currentPrice) { var newHigh = currentPrice > highPrice; var newLow = currentPrice < lowPrice; if (newHigh) { highPrice = currentPrice; } if (newLow) { lowPrice = currentPrice; } if (isShortPosition && newLow) { //stopLoss.Update(new UpdateOrderFields{ StopPrice = currentPrice * 1.02m }); } if (!isShortPosition && newHigh) { //stopLoss.Update(new UpdateOrderFields{ StopPrice = currentPrice * 0.98m }); } } public override void OnOrderEvent(OrderEvent orderEvent) { if (!orderEvent.Status.IsClosed()) { return; } var filledOrderId = orderEvent.OrderId; if (profitTarget != null && stopLoss != null) { if (profitTarget.OrderId == filledOrderId)// && stopLoss.Status.IsOpen()) { Log(Time+": Cancelling stop loss"); stopLoss.Cancel(); } if (stopLoss.OrderId == filledOrderId)// && profitTarget.Status.IsOpen()) { Log(Time+": Cancelling profit target"); profitTarget.Cancel(); } } base.OnOrderEvent(orderEvent); } } }
using QuantConnect.Algorithm; using QuantConnect.Indicators; using System; using QuantConnect.Orders; using QuantConnect.Data.Market; namespace QuantConnect.RsiMovingAverage { public partial class RsiMovingAverageAlgorithm : QCAlgorithm { string symbol = "SPY"; // string symbol = "C"; // string symbol = "SBUX"; // string symbol = "MSFT"; SimpleMovingAverage shortMovingAverage; SimpleMovingAverage longMovingAverage; RelativeStrengthIndex rsi; DateTime purchaseDate; TimeSpan holdPeriod; OrderTicket currentOrder; OrderTicket profitTarget; OrderTicket stopLoss; decimal highPrice = decimal.MinValue; decimal lowPrice = decimal.MaxValue; bool isShortPosition; public override void Initialize() { SetStartDate(2000, 1, 1); SetEndDate(2010, 1, 1); SetCash(25000); AddSecurity(SecurityType.Equity, symbol, Resolution.Daily); shortMovingAverage = SMA(symbol, 50, Resolution.Daily); longMovingAverage = SMA(symbol, 200, Resolution.Daily); rsi = RSI(symbol, 2, MovingAverageType.Simple, Resolution.Daily); holdPeriod = TimeSpan.FromDays(5); } public void OnData(TradeBars data) { var currentOrderIsFilled = true; if (currentOrder != null) { currentOrderIsFilled = currentOrder.Status.IsFill(); } var inMarket = Portfolio.Securities[symbol].HoldStock; if (stopLoss != null) { inMarket = inMarket && stopLoss.Status.IsOpen(); } if (profitTarget != null) { inMarket = inMarket && profitTarget.Status.IsOpen(); } var currentPrice = data[symbol].Price; if (currentOrderIsFilled && !inMarket) { TryEnterMarket(currentPrice); } else if (currentOrderIsFilled && inMarket) { TryExitMarket(currentPrice); } } private void TryEnterMarket(decimal currentPrice) { if (IsLongSignal()) { EnterLong(currentPrice); } else if (IsShortSignal()) { EnterShort(currentPrice); } } private void TryExitMarket(decimal currentPrice) { if (IsExitSignal(currentPrice)) { ExitMarket(); highPrice = decimal.MinValue; lowPrice = decimal.MaxValue; } else { UpdateStopLoss(currentPrice); } } } }