HistoryInfoEaStrategy repliziert das MT4-Hilfsprogramm "HistoryInfo" auf StockSharp. Statt Text auf dem MetaTrader-Chart zu zeichnen, lauscht die Strategie dem OnNewMyTrade-Stream und aggregiert Statistiken für Trades, die einem gewählten Filter entsprechen. Die aggregierten Werte werden über die Eigenschaft LastSnapshot bereitgestellt und im Strategielog gespiegelt, sodass eine GUI oder ein Automatisierungsskript die Zusammenfassung in beliebiger Form anzeigen kann.
Die Strategie registriert niemals eigene Orders. Sie ist dafür gedacht, neben anderen automatisierten oder manuellen Strategien zu laufen, während diese Orders an den Broker senden. Jeder ausgeführte Trade, der den Filter erfüllt, trägt zu den Summen bei.
Parameter
Parameter
Beschreibung
FilterType
Auswahlmodus, der bestimmt, wie Trades abgeglichen werden. Unterstützte Werte: CountByUserOrderId, CountByComment, CountBySecurity.
MagicNumber
Erwartete Order.UserOrderId. Wird nur verwendet, wenn FilterType gleich CountByUserOrderId ist. Leer lassen, um diesen Filter zu deaktivieren.
OrderComment
Präfix, das zu Order.Comment passen muss. Nur für den Modus CountByComment relevant. Der Standardwert (\"OrdersComment\") imitiert den Platzhalter des MT4-Skripts und passt normalerweise zu keiner Order, bis er ersetzt wird.
SecurityId
Kennung des Instruments (Security.Id), die passen muss, wenn FilterType gleich CountBySecurity ist. Der Standard (\"OrdersSymbol\") ist ein Platzhalter.
Aggregierte Kennzahlen
LastSnapshot wird nach jedem passenden Trade aktualisiert. Es enthält:
FirstTrade / LastTrade - Zeitstempel des frühesten und spätesten verarbeiteten Trades.
TotalVolume - kumuliertes ausgeführtes Volumen in den Volumeneinheiten des Trades (Lots, Kontrakte usw.).
TotalProfit - Summe von MyTrade.PnL abzüglich gemeldeter Kommission, was den realisierten Gewinn in Kontowährung ergibt.
TotalPips - Gewinn, umgerechnet in Pips mit Security.PriceStep, Security.StepPrice und MT4-ähnlicher Stellenbehandlung (5/3 Stellen multiplizieren den Punkt mit 10).
TradeCount - Anzahl der Trades, die den Filter passiert haben.
Dieselbe Information wird in einer einzelnen Zeile ins Strategielog geschrieben und emuliert die MT4-Comment()-Ausgabe für schnelle Prüfung.
Verwendung
Binden Sie die Strategie an dasselbe Portfolio und Wertpapier, das andere Strategien für Orderübermittlung verwenden.
Wählen Sie den gewünschten FilterType und füllen Sie den zugehörigen Parameter aus (Magic Number, Kommentarpräfix oder Wertpapierkennung).
Starten Sie die Strategie. Sobald der erste Trade ausgeführt wird, der den Kriterien entspricht, sind die Summen über LastSnapshot und das Log verfügbar.
Die Zähler werden bei jedem Strategieneustart oder manuellen Reset automatisch zurückgesetzt.
Hinweis: Zur Berechnung von Pip-Summen benötigt die Strategie korrekte Instrumentenmetadaten. Stellen Sie sicher, dass Security.PriceStep und Security.StepPrice in der Board-Definition konfiguriert sind. Fehlt einer der Werte, bleibt der Pip-Zähler bei null, während der Gewinnwert weiter akkumuliert.
Hinweise zur Umstellung
Der MT4-Code iterierte auf jedem Tick über OrdersHistoryTotal(). In StockSharp reagiert die Strategie auf Echtzeit-MyTrade-Benachrichtigungen; es gibt also kein Polling und Berechnungen aktualisieren sich sofort bei einem Fill.
MT4 speicherte Gewinn als OrderProfit + OrderCommission + OrderSwap. StockSharp liefert realisierten Gewinn über MyTrade.PnL und Kommission separat; Swap ist normalerweise bereits im PnL enthalten. Die Portierung zieht Kommission von PnL ab, um mit dem ursprünglichen Bericht konsistent zu bleiben.
Die String-Platzhalter (\"OrdersComment\", \"OrdersSymbol\") bleiben erhalten, um den ursprünglichen Defaults zu ähneln. Ersetzen Sie sie vor dem Start durch tatsächliche Werte, wenn Sie Treffer erwarten.
Visuelle Chart-Ausgabe aus MT4 wird durch strukturierte Daten (LastSnapshot) und Logzeilen ersetzt, damit Integratoren selbst entscheiden können, wie die Information dargestellt wird.
Die Strategie vermeidet absichtlich das Erstellen neuer Orders und kann daher im Read-only-Modus gestartet werden, um fremde Trade-Streams zu analysieren, ohne einzugreifen.
Erweiterungsideen
Abonnieren Sie LastSnapshot-Aktualisierungen und leiten Sie die Information an ein Dashboard oder einen Telemetrie-Collector weiter.
Erweitern Sie die Klasse um zusätzliche Filter (zum Beispiel nach Portfolio oder benutzerdefinierten Strategie-Tags), wenn der Connector die relevanten Metadaten bereitstellt.
Kombinieren Sie die Strategie mit einem periodischen Timer, um historische Zusammenfassungen in einen CSV/JSON-Bericht zu exportieren.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class HistoryInfoEaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public HistoryInfoEaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class history_info_ea_strategy(Strategy):
def __init__(self):
super(history_info_ea_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(history_info_ea_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(history_info_ea_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return history_info_ea_strategy()