using NinjaTrader.Cbi; using NinjaTrader.CQG.ProtoBuf; using NinjaTrader.Data; using NinjaTrader.Gui; using NinjaTrader.Gui.Tools; using NinjaTrader.NinjaScript.DrawingTools; using NinjaTrader.NinjaScript.Indicators; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Windows; using System.Windows.Media; using Order = NinjaTrader.Cbi.Order; // Added protection-related using statements using System.Security.Cryptography; using System.Text; using System.Runtime.InteropServices; using System.Net.Http; namespace NinjaTrader.NinjaScript.Strategies { [CategoryOrder(Setup, 1)] [CategoryOrder(GlobalSettings, 2)] [CategoryOrder(EntrySettings, 4)] [CategoryOrder(FilterSettings, 5)] [CategoryOrder(ExitSettings, 6)] public class EmptyStrategy:Strategy { // Added System Information Structure for hardware ID [DllImport("kernel32.dll")] private static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo); [StructLayout(LayoutKind.Sequential)] private struct SYSTEM_INFO { public ushort wProcessorArchitecture; public ushort wReserved; public uint dwPageSize; public IntPtr lpMinimumApplicationAddress; public IntPtr lpMaximumApplicationAddress; public IntPtr dwActiveProcessorMask; public uint dwNumberOfProcessors; public uint dwProcessorType; public uint dwAllocationGranularity; public ushort wProcessorLevel; public ushort wProcessorRevision; } // Added License Properties and Fields private bool isValidated = false; private static Dictionary licenseCache = new Dictionary(); private const int CACHE_DURATION_HOURS = 24; private string cachedHardwareId = null; [NinjaScriptProperty] [Display(Name = "License Key", Description = "Enter your Whop license key", Order = 1, GroupName = "License")] public string LicenseKey { get; set; } // Hardware ID Generation Method private string GetHardwareId() { if (!string.IsNullOrEmpty(cachedHardwareId)) return cachedHardwareId; try { var hardwareInfo = new StringBuilder(); GetSystemInfo(out SYSTEM_INFO sysInfo); // Collect hardware information hardwareInfo.Append(sysInfo.dwProcessorType) .Append(sysInfo.wProcessorArchitecture) .Append(sysInfo.wProcessorLevel) .Append(sysInfo.wProcessorRevision) .Append(sysInfo.dwNumberOfProcessors); // Add environment info hardwareInfo.Append(Environment.ProcessorCount) .Append(Environment.MachineName) .Append(Environment.OSVersion.Version.ToString()) .Append(Environment.UserName) .Append(Environment.SystemDirectory); // Hash the hardware info using (var sha256 = SHA256.Create()) { var bytes = System.Text.Encoding.UTF8.GetBytes(hardwareInfo.ToString()); var hash = sha256.ComputeHash(bytes); cachedHardwareId = BitConverter.ToString(hash).Replace("-", ""); } return cachedHardwareId; } catch (Exception ex) { Log($"Error generating hardware ID: {ex.Message}", LogLevel.Error); return null; } } // License Validation Method private bool ValidateLicense() { if (string.IsNullOrEmpty(LicenseKey)) return false; var hwid = GetHardwareId(); if (string.IsNullOrEmpty(hwid)) return false; // Check cache if (licenseCache.ContainsKey(LicenseKey)) { var cacheTime = licenseCache[LicenseKey]; if (DateTime.Now.Subtract(cacheTime).TotalHours < CACHE_DURATION_HOURS) return true; licenseCache.Remove(LicenseKey); } try { using (var client = new System.Net.Http.HttpClient()) { const string apiKey = "A6FHGMmhg3PXodjW1XFmYx7Tg5cQgQlEETvTckfIQ1o"; client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}"); // Send HWID in metadata var hwidMetadata = $"{{\"metadata\": {{\"HWID\": \"{hwid}\"}}}}"; var content = new StringContent(hwidMetadata, System.Text.Encoding.UTF8, "application/json"); // Validate license with Whop API var requestUrl = $"https://api.whop.com/api/v2/memberships/{LicenseKey}/validate_license"; var response = client.PostAsync(requestUrl, content).Result.Content.ReadAsStringAsync().Result; // Check if license is valid bool isValid = (response.Contains("\"status\":\"active\"") || response.Contains("\"status\":\"trialing\"") || response.Contains("\"status\":\"completed\"")) && response.Contains("\"valid\":true"); if (isValid) { licenseCache[LicenseKey] = DateTime.Now; isValidated = true; return true; } return false; } } catch (Exception) { // Offline grace period check if (licenseCache.ContainsKey(LicenseKey)) { var cacheTime = licenseCache[LicenseKey]; if (DateTime.Now.Subtract(cacheTime).TotalHours < (CACHE_DURATION_HOURS * 2)) return true; } return false; } } // Strategy Stop Method private void StopStrategy() { try { if (State != State.SetDefaults && State != State.Terminated) { Log("Strategy stopping due to invalid license.", LogLevel.Error); IsEnabled = false; State = State.Terminated; } } catch (Exception ex) { Log($"Error in StopStrategy: {ex.Message}", LogLevel.Error); } } #region Constants private const string SystemVersion = " V1.5"; private const string StrategyName = "Volume and Trend Bot - Vincere Trading"; public override string DisplayName { get { return StrategyName + SystemVersion; } } private const string Setup = "Setup"; private const string GlobalSettings = "Global Settings"; private const string EntrySettings = "Entry Settings"; private const string FilterSettings = "Filter Settings"; private const string ExitSettings = "Exit Settings"; #endregion #region Parameters [NinjaScriptProperty] [Display(Name = "Max Session Loss On/Off", GroupName = GlobalSettings, Order = 20)] public bool MaxLossIsOn { get; set; } [NinjaScriptProperty] [Display(Name = "Max Session Loss", GroupName = GlobalSettings, Order = 21)] public double MaxSessionLoss { get; set; } [NinjaScriptProperty] [Display(Name = "Max Session Win On/Off", GroupName = GlobalSettings, Order = 22)] public bool MaxWinIsOn { get; set; } [NinjaScriptProperty] [Display(Name = "Max Session Profit", GroupName = GlobalSettings, Order = 23)] public double MaxSessionProfit { get; set; } [NinjaScriptProperty] [Display(Name = "Backtest", GroupName = GlobalSettings, Order = 25)] public bool Backtest { get; set; } [Display(Name = "Position Size", Order = 9, GroupName = EntrySettings)] public int PosSize { get; set; } [Display(Name = "Entry Order Tick Offset", Order = 10, GroupName = EntrySettings)] public int EntryOrderTickOffset { get; set; } [Display(Name = "MA-1 Period", Order = 11, GroupName = EntrySettings)] public int Ma1Period { get; set; } [Display(Name = "MA-2 Period", Order = 12, GroupName = EntrySettings)] public int Ma2Period { get; set; } [Display(Name = "MA-3 Period", Order = 13, GroupName = EntrySettings)] public int Ma3Period { get; set; } [Display(Name = "Min Bar Size Ticks", Order = 14, GroupName = EntrySettings)] public int MinBarSizeTicks { get; set; } [Display(Name = "Order Active Bars", Order = 15, GroupName = EntrySettings)] public int OrderActiveBars { get; set; } [NinjaScriptProperty] [Display(Name = "Trade Window", GroupName = EntrySettings, Order = 23)] public bool TradeWindow1IsOn { get; set; } [PropertyEditor("NinjaTrader.Gui.Tools.AutoCloseTimeEditorKey")] [NinjaScriptProperty] [Display(Name = "Trade Start", GroupName = EntrySettings, Order = 24)] public DateTime TradeStart1 { get; set; } [PropertyEditor("NinjaTrader.Gui.Tools.AutoCloseTimeEditorKey")] [NinjaScriptProperty] [Display(Name = "Trade End", GroupName = EntrySettings, Order = 25)] public DateTime TradeEnd1 { get; set; } [NinjaScriptProperty] [Display(Name = "Reverse Trade", GroupName = EntrySettings, Order = 26)] public bool ReverseTradeIsOn { get; set; } [NinjaScriptProperty] [Display(Name = "Profit Target Ticks", GroupName = ExitSettings, Order = 14)] public double ProfitTargetTicks { get; set; } [NinjaScriptProperty] [Display(Name = "Stop Loss Ticks", GroupName = ExitSettings, Order = 15)] public double StopLossTicks { get; set; } [NinjaScriptProperty] [Display(Name = "Trail", GroupName = ExitSettings, Order = 16)] public bool TrailIsOn { get; set; } [NinjaScriptProperty] [Display(Name = "Trail By Ticks", GroupName = ExitSettings, Order = 17)] public int TrailByTicks { get; set; } [NinjaScriptProperty] [Display(Name = "Reverse On Stop", GroupName = ExitSettings, Order = 18)] public bool ReverseOnStop { get; set; } [NinjaScriptProperty] [Display(Name = "Max Reverse", GroupName = ExitSettings, Order = 19)] public int MaxReverse { get; set; } public enum ReverseOrderType { Market, StopMarket } [NinjaScriptProperty] [Display(Name = "Reverse Order Type", GroupName = ExitSettings, Order = 20)] public ReverseOrderType MyReverseOrderType { get; set; } [NinjaScriptProperty] [Display(Name = "Reverse Offset Ticks", GroupName = ExitSettings, Order = 21)] public int ReverseOffsetTicks { get; set; } #endregion #region Values #endregion #region Init private SolidColorBrush _bgColor; protected override void OnStateChange() { switch (State) { case State.SetDefaults: LicenseKey = string.Empty; SetDefaults(); SetParameters(); break; case State.Configure: if (!ValidateLicense()) { Log("Invalid license key.", LogLevel.Error); StopStrategy(); return; } ClearOutputWindow(); SuperImpose(); InitIndicators(); _bgColor = new SolidColorBrush(Colors.Green) { Opacity = 0.25 }; _bgColor.Freeze(); break; case State.DataLoaded: break; case State.Terminated: break; case State.Realtime: break; } } private void SuperImpose() { if (Calculate == Calculate.OnEachTick || Calculate == Calculate.OnPriceChange) Calculate = Calculate.OnBarClose; if (IsExitOnSessionCloseStrategy) IsExitOnSessionCloseStrategy = false; TraceOrders = false; } private void SetDefaults() { Name = StrategyName + SystemVersion; Calculate = Calculate.OnBarClose; IsExitOnSessionCloseStrategy = false; IsUnmanaged = true; BarsRequiredToTrade = 0; IsInstantiatedOnEachOptimizationIteration = true; RealtimeErrorHandling = RealtimeErrorHandling.StopCancelCloseIgnoreRejects; ShowTransparentPlotsInDataBox = true; } private void SetParameters() { PosSize = 1; StopLossTicks = 20; ProfitTargetTicks = 20; MaxSessionLoss = 500; MaxSessionProfit = 500; Ma1Period = 7; Ma2Period = 14; Ma3Period = 50; TradeStart1 = new DateTime(2020, 01, 01, 9, 30, 0); TradeEnd1 = new DateTime(2020, 01, 01, 16, 30, 0); EntryOrderTickOffset = 1; MinBarSizeTicks = 5; TrailByTicks = 10; OrderActiveBars = 1; MaxReverse = 1; ReverseOffsetTicks = 1; } private Indicator _ma1, _ma2, _ma3; private void InitIndicators() { _ma1 = EMA(Ma1Period); _ma1.Plots[0].Brush = Brushes.Orange; _ma2 = EMA(Ma2Period); _ma2.Plots[0].Brush = Brushes.BlueViolet; _ma3 = EMA(Ma3Period); _ma3.Plots[0].Brush = Brushes.Blue; AddChartIndicator(_ma1); AddChartIndicator(_ma2); AddChartIndicator(_ma3); } #endregion #region Business protected override void OnBarUpdate() { if (CurrentBar < Ma3Period * 3) return; if (!ValidateLicense()) { StopStrategy(); return; } Reset(); ColorInsideTradeWindow(TradeStart1, TradeEnd1, TradeWindow1IsOn); SetSignal(); OpenPositions(); ExitModule(); } private bool _clearOnClose; private void Reset() { if (Time[0].Date != Time[1].Date) { _stopTradingForSession = false; if (Position.MarketPosition == MarketPosition.Flat) _positions.Clear(); if (Position.MarketPosition != MarketPosition.Flat) _clearOnClose = true; } if (_reverseStopPlaced) { if (_entryOrder != null) CancelOrder(_entryOrder); _reverseCount = 0; } } private bool _enterLong; private bool _enterShort; private void SetSignal() { _enterLong = VolumeIsOk() && BarColorIsOk(true) && MaAreOk(true) && IsInsideTradeWindow() && BarSizeIsOk(); _enterShort = VolumeIsOk() && BarColorIsOk(false) && MaAreOk(false) && IsInsideTradeWindow() && BarSizeIsOk(); } private bool IsInsideTradeWindow() { if (!TradeWindow1IsOn) return true; var timeNow = ToTime(Time[0]); if (TradeStart1 < TradeEnd1) { if (timeNow >= ToTime(TradeStart1) && timeNow <= ToTime(TradeEnd1)) { return true; } } else if (TradeStart1 > TradeEnd1) { if (timeNow >= ToTime(TradeStart1) || timeNow <= ToTime(TradeEnd1)) { return true; } } return false; } private bool BarSizeIsOk() { return (High[0] - Low[0]) / TickSize >= MinBarSizeTicks && (High[1] - Low[1]) / TickSize >= MinBarSizeTicks; } private bool VolumeIsOk() { return Volume[0] > Volume[1]; } private bool BarColorIsOk(bool isLong) { if (isLong) return Close[0] > Open[0] && Close[1] > Open[1]; return Close[0] < Open[0] && Close[1] < Open[1]; } private bool MaAreOk(bool isLong) { if (isLong) return _ma1[0] > _ma2[0] && _ma2[0] > _ma3[0]; return _ma1[0] < _ma2[0] && _ma2[0] < _ma3[0]; } private void ColorInsideTradeWindow(DateTime start, DateTime end, bool isOn) { if (!isOn) return; var timeNow = ToTime(Time[0]); if (start < end) { if (timeNow >= ToTime(start) && timeNow <= ToTime(end)) { BackBrush = _bgColor; } } else if (start > end) { if (timeNow >= ToTime(start) || timeNow <= ToTime(end)) { BackBrush = _bgColor; } } } private bool _entryOrderPlaced; private int _barsCount; private void OpenPositions() { if (Position.MarketPosition != MarketPosition.Flat) return; if (State == State.Historical && !Backtest) return; if (_stopTradingForSession) { if (_entryOrder != null) CancelOrder(_entryOrder); _entryOrderPlaced = false; _barsCount = 0; return; } if (_enterLong || _enterShort || _barsCount >= OrderActiveBars) { if (_entryOrder != null) CancelOrder(_entryOrder); _entryOrderPlaced = false; _barsCount = 0; } if (_entryOrderPlaced) _barsCount++; if (!ReverseTradeIsOn) { EnterTrendStopMarketOrders(); } if (ReverseTradeIsOn) { EnterFlatLimitOrders(); } } private void EnterTrendStopMarketOrders() { if (_enterLong) { var entryPrice = High[0] + EntryOrderTickOffset * TickSize; if (entryPrice >= GetCurrentAsk()) { PlaceStopMarketEntryOrder(true, entryPrice); _barsCount++; _entryOrderPlaced = true; } } if (_enterShort) { var entryPrice = Low[0] - EntryOrderTickOffset * TickSize; if (entryPrice <= GetCurrentBid()) { PlaceStopMarketEntryOrder(false, entryPrice); _barsCount++; _entryOrderPlaced = true; } } } private void EnterFlatLimitOrders() { if (_enterLong) { var entryPrice = High[0] + EntryOrderTickOffset * TickSize; PlaceLimitMarketEntryOrder(false, entryPrice); _barsCount++; _entryOrderPlaced = true; } if (_enterShort) { var entryPrice = Low[0] - EntryOrderTickOffset * TickSize; PlaceLimitMarketEntryOrder(true, entryPrice); _barsCount++; _entryOrderPlaced = true; } } private void ExitModule() { Trail(Close[0]); } protected override void OnMarketData(MarketDataEventArgs marketDataUpdate) { if (marketDataUpdate.MarketDataType != MarketDataType.Last) return; Trail(marketDataUpdate.Price); } private void Trail(double price) { if (!TrailIsOn) return; if (Position.MarketPosition == MarketPosition.Long) { var newStop = price - TrailByTicks * TickSize; if (newStop > _stop && newStop < GetCurrentBid()) { _stop = newStop; ChangeStopExitOrder(); } } if (Position.MarketPosition == MarketPosition.Short) { var newStop = price + TrailByTicks * TickSize; if (newStop < _stop && newStop > GetCurrentAsk()) { _stop = newStop; ChangeStopExitOrder(); } } } private void ExitPositions() { if (Position.MarketPosition == MarketPosition.Long) { PlaceMarketExitOrder(true); } if (Position.MarketPosition == MarketPosition.Short) { PlaceMarketExitOrder(false); } } #endregion #region Orders private const string EnterLongName = "Enter Long"; private const string EnterShortName = "Enter Short"; private const string ExitLongStopName = "Stop Long"; private const string ExitShortStopName = "Stop Short"; private const string ExitLongProfitName = "Profit Long"; private const string ExitShortProfitName = "Profit Short"; private const string MarketCloseLong = "Exit Long Market"; private const string MarketCloseShort = "Exit Short Market"; private Order _exitMarketOrder; private Order _entryOrder; private Order _exitStopOrder; private Order _entryOrderShort; private Order _entryOrderLong; private Order _exitProfitOrder; private double _stop; private double _profit; private void PlaceMarketEntryOrder(bool isLong) { if (isLong) { _entryOrder = SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.Market, PosSize, 0, 0, "", EnterLongName); } if (!isLong) { _entryOrder = SubmitOrderUnmanaged(0, OrderAction.SellShort, OrderType.Market, PosSize, 0, 0, "", EnterShortName); } } private void PlaceStopMarketEntryOrder(bool isLong, double price) { if (isLong) { _entryOrder = SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.StopMarket, PosSize, 0, price, "", EnterLongName); } if (!isLong) { _entryOrder = SubmitOrderUnmanaged(0, OrderAction.SellShort, OrderType.StopMarket, PosSize, 0, price, "", EnterShortName); } } private void PlaceLimitMarketEntryOrder(bool isLong, double price) { if (isLong) { _entryOrder = SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.Limit, PosSize, price, 0, "", EnterLongName); } if (!isLong) { _entryOrder = SubmitOrderUnmanaged(0, OrderAction.SellShort, OrderType.Limit, PosSize, price, 0, "", EnterShortName); } } private void PlaceMarketExitOrder(bool isLong) { if (isLong) { _exitMarketOrder = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Market, Position.Quantity, 0, 0, "", MarketCloseLong); } else if (!isLong) { _exitMarketOrder = SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.Market, Position.Quantity, 0, 0, "", MarketCloseShort); } } private void ChangeStopExitOrder() { ChangeOrder(_exitStopOrder, Position.Quantity, 0, _stop); } private void ChangeProfitExitOrder() { ChangeOrder(_exitProfitOrder, Position.Quantity, _profit, 0); } private void PlaceStopExitOrders(bool isStopLong) { if (isStopLong) { _exitStopOrder = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, PosSize, 0, _stop, "", ExitLongStopName); } if (!isStopLong) { _exitStopOrder = SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.StopMarket, PosSize, 0, _stop, "", ExitShortStopName); } } private void PlaceProfitExitOrders(bool isStopLong) { if (isStopLong) { _exitProfitOrder = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Limit, PosSize, _profit, 0, "", ExitLongProfitName); } if (!isStopLong) { _exitProfitOrder = SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.Limit, PosSize, _profit, 0, "", ExitShortProfitName); } } #endregion #region Execution protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string comment) { } private bool _orderIgnored; protected override void OnOrderTrace(DateTime timestamp, string message) { //base.OnOrderTrace(timestamp, message); if (message.Contains("Ignored")) { _orderIgnored = true; } } protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time) { if (!IsFilled(execution.Order)) return; ManageOrders(execution); } private bool IsFilled(Order order) { if (order.OrderState == OrderState.Filled) return true; if (order.OrderState == OrderState.PartFilled) { if (order.Filled == order.Quantity) { return true; } } return false; } private int _reverseCount; private bool _reverseStopPlaced; private void ManageOrders(Execution ex) { var orderName = ex.Order.Name; if (orderName == EnterLongName || orderName == EnterShortName) { _entryOrderPlaced = false; _barsCount = 0; var stopSize = StopLossTicks * TickSize; var profitSize = ProfitTargetTicks * TickSize; if (orderName == EnterLongName) { _stop = ex.Order.AverageFillPrice - stopSize; _profit = ex.Order.AverageFillPrice + profitSize; PlaceStopExitOrders(true); PlaceProfitExitOrders(true); CreatePosition(true, ex.Order); } if (orderName == EnterShortName) { _stop = ex.Order.AverageFillPrice + stopSize; _profit = ex.Order.AverageFillPrice - profitSize; PlaceStopExitOrders(false); PlaceProfitExitOrders(false); CreatePosition(true, ex.Order); } } if (orderName == ExitLongStopName || orderName == ExitShortStopName) { if (_exitProfitOrder != null) CancelOrder(_exitProfitOrder); ClosePosition(ex.Order); if (ReverseOnStop) { _reverseCount++; if (_reverseCount <= MaxReverse) { if (MyReverseOrderType == ReverseOrderType.StopMarket) { if (orderName == ExitLongStopName) PlaceStopMarketEntryOrder(false, ex.Order.AverageFillPrice - TickSize * ReverseOffsetTicks); if (orderName == ExitShortStopName) PlaceStopMarketEntryOrder(true, ex.Order.AverageFillPrice + TickSize * ReverseOffsetTicks); _reverseStopPlaced = true; } if (MyReverseOrderType == ReverseOrderType.Market) { if (orderName == ExitLongStopName) PlaceMarketEntryOrder(false); if (orderName == ExitShortStopName) PlaceMarketEntryOrder(true); } } else { _reverseCount = 0; } } } if (orderName == ExitLongProfitName || orderName == ExitShortProfitName) { if (_exitStopOrder != null) CancelOrder(_exitStopOrder); ClosePosition(ex.Order); _reverseCount = 0; } if (orderName == MarketCloseLong || orderName == MarketCloseShort) { if (_exitStopOrder != null) CancelOrder(_exitStopOrder); if (_exitProfitOrder != null) CancelOrder(_exitProfitOrder); _reverseCount = 0; } } class MyPosition { public List Trades { get; set; } public bool IsOpen { get; set; } public bool IsLong { get; set; } public double Pnl { get; set; } } class MyTrade { public double EntryPrice { get; set; } public double ExitPrice { get; set; } public int Qnt { get; set; } public double Pnl { get; set; } } private List _positions = new List(); private void CreatePosition(bool isLong, Order order) { var pos = new MyPosition() { Trades = new List(), IsOpen = true, IsLong = isLong }; pos.Trades.Add(new MyTrade() { EntryPrice = order.AverageFillPrice, Qnt = order.Quantity }); _positions.Add(pos); } private bool _stopTradingForSession; private void ClosePosition(Order order) { var pos = _positions[_positions.Count - 1]; pos.IsOpen = false; var commissionPerUnit = 0d; if (Account.Commission != null) { commissionPerUnit = Account.Commission.ByMasterInstrument[Instrument.MasterInstrument].PerUnit; } foreach (var trade in pos.Trades) { trade.ExitPrice = order.AverageFillPrice; if (pos.IsLong) { trade.Pnl = (trade.ExitPrice - trade.EntryPrice) * trade.Qnt * Instrument.MasterInstrument.PointValue; trade.Pnl = trade.Pnl - (commissionPerUnit * trade.Qnt * 2); } if (!pos.IsLong) { trade.Pnl = (trade.EntryPrice - trade.ExitPrice) * trade.Qnt * Instrument.MasterInstrument.PointValue; trade.Pnl = trade.Pnl - (commissionPerUnit * trade.Qnt * 2); } } var positionPnl = pos.Trades.Sum(x => x.Pnl); pos.Pnl = positionPnl; var sessionPnl = _positions.Sum(p => p.Pnl); if (MaxWinIsOn && sessionPnl > MaxSessionProfit) { var color = Brushes.DarkGreen; Draw.Text(this, CurrentBar + "SPNL", true, "Session PNL " + sessionPnl, 0, Low[0] - TickSize * 20, 0, Brushes.White, new SimpleFont("Arial", 10), TextAlignment.Center, Brushes.Black, color, 80); _stopTradingForSession = true; } if (MaxLossIsOn && sessionPnl < MaxSessionLoss * -1) { var color = Brushes.DarkRed; Draw.Text(this, CurrentBar + "SPNL", true, "Session PNL " + sessionPnl, 0, Low[0] - TickSize * 20, 0, Brushes.White, new SimpleFont("Arial", 10), TextAlignment.Center, Brushes.Black, color, 80); _stopTradingForSession = true; } ClearOnClose(); } private void ClearOnClose() { if (_clearOnClose) { _positions.Clear(); _clearOnClose = false; } } #endregion } }