Estratégia TradeEATemplateNews
Visão geral
A Estratégia TradeEATemplateNews é uma conversão em C# do consultor especializado MetaTrader 4 "Trade EA Template for News". O sistema original pausava o trading em torno de eventos econômicos programados baixados de sites externos. Este port do StockSharp mantém as ideias principais enquanto as adapta à API de alto nível:
- Usa velas completadas do período configurado (H1 por padrão).
- Opera somente quando a conta está flat, exatamente como o modelo MQL que exigia zero ordens abertas.
- Aplica um bloqueio manual de notícias econômicas que impede entradas antes e depois dos eventos dependendo de sua importância.
- Cria automaticamente brackets protetores de stop-loss e take-profit a 100 pontos do preço de execução (convertidos pelo passo do instrumento).
Lógica de trading
- Cada vela completada aciona um recálculo do calendário de notícias. A estratégia armazena o preço de abertura da vela anterior para que a próxima barra possa comparar seu fechamento com a abertura anterior.
- Se o tempo atual cair dentro de qualquer janela de bloqueio configurada, a estratégia cancela ordens pendentes e não abre novas operações.
- Quando nenhuma posição está aberta e o trading é permitido:
- Uma posição comprada é aberta se a última vela fechar acima do preço de abertura da vela anterior.
- Uma posição vendida é aberta se a última vela fechar abaixo do preço de abertura da vela anterior.
- Os níveis de stop-loss e take-profit são expressos em pontos (
TakeProfitPoints e StopLossPoints) e convertidos em deslocamentos de preço absolutos usando o valor Step do instrumento.
Calendário de notícias manual
O especialista original baixava dados de investing.com ou DailyFX. Para portabilidade, a versão StockSharp espera um calendário curado manualmente fornecido através do parâmetro NewsEventsDefinition. O formato aceita uma lista de entradas separadas por ponto-e-vírgula ou quebras de linha. Cada entrada deve conter pelo menos três campos separados por vírgulas:
AAAA-MM-DD HH:MM,MOEDAS,IMPORTÂNCIA[,TÍTULO]
AAAA-MM-DD HH:MM — início do evento em UTC. O parâmetro opcional TimeZoneOffsetHours desloca todos os tempos processados pelo valor solicitado (por exemplo, defina 3 para UTC+3).
MOEDAS — códigos de moeda ou identificadores de instrumentos como USD, EUR, EUR/USD. Múltiplos códigos podem ser separados com /, ,, ;, | ou espaços.
IMPORTÂNCIA — palavra-chave de importância. Valores reconhecidos: Low, Medium, Mid, Midle, Moderate, High, NFP, strings contendo Nonfarm ou Non-farm.
TÍTULO — descrição de texto livre opcional que será impressa nas mensagens de registro.
Exemplo:
2024-03-01 13:30,USD,High,Nonfarm Payrolls;2024-03-01 15:00,USD,Low,Factory Orders
Janelas de bloqueio
UseLowNews, UseMediumNews, UseHighNews e UseNfpNews alternam quais eventos são considerados.
LowMinutesBefore/After, MediumMinutesBefore/After, HighMinutesBefore/After e NfpMinutesBefore/After determinam quantos minutos em torno do evento o trading deve ser desabilitado.
OnlySymbolNews restringe o bloqueio a entradas cujos códigos de moeda correspondam ao instrumento atual (por exemplo, EURUSD resulta no par {EUR, USD}). Desative-o para pausar o trading em cada evento.
- A estratégia mantém apenas o evento de maior importância ativo em qualquer momento. Mensagens de registro informativas anunciam a razão do estado atual e a próxima publicação programada.
Parâmetros
| Parâmetro |
Descrição |
Padrão |
CandleType |
Tipo de dados de velas para assinar. Padrão de 1 hora. |
1h |
UseLowNews |
Habilitar eventos de baixa importância. |
true |
LowMinutesBefore / LowMinutesAfter |
Minutos antes/depois de notícias de baixo impacto para bloquear entradas. |
15 / 15 |
UseMediumNews |
Habilitar eventos de importância média. |
true |
MediumMinutesBefore / MediumMinutesAfter |
Minutos antes/depois de notícias de impacto médio. |
30 / 30 |
UseHighNews |
Habilitar eventos de alta importância. |
true |
HighMinutesBefore / HighMinutesAfter |
Minutos antes/depois de notícias de alto impacto. |
60 / 60 |
UseNfpNews |
Habilitar o indicador de Non-farm Payrolls. |
true |
NfpMinutesBefore / NfpMinutesAfter |
Minutos antes/depois de eventos NFP. |
180 / 180 |
OnlySymbolNews |
Filtrar o calendário pelos códigos de moeda do instrumento atual. |
true |
NewsEventsDefinition |
String de descrição do calendário econômico manual. |
vazio |
TimeZoneOffsetHours |
Deslocamento aplicado a cada evento processado (UTC por padrão). |
0 |
TakeProfitPoints |
Distância em pontos para a ordem protetora de take-profit. |
100 |
StopLossPoints |
Distância em pontos para a ordem protetora de stop-loss. |
100 |
Volume é herdado de Strategy e deve ser configurado de acordo com o tamanho de posição desejado.
Diferenças da versão MQL
- Sem download HTTP automático — o usuário fornece a lista de notícias manualmente, o que evita dependências externas e mantém a conversão determinista.
- Os rótulos de gráfico e linhas verticais são substituídos por mensagens de registro que descrevem o evento ativo ou próximo.
- O especialista MQL abria ordens com tamanho de lote fixo
0.01; no StockSharp o tamanho de posição vem da propriedade Volume.
- Toda a lógica é implementada com a API de assinatura de velas de alto nível preservando o comportamento consciente de notícias do modelo.
Notas de implantação
- Preencha
NewsEventsDefinition antes de iniciar a estratégia ou atualize-o, pare e reinicie para recarregar o calendário.
- Ajuste
TimeZoneOffsetHours e os parâmetros de minutos antes/depois para corresponder à sua sessão de trading.
- Defina
Volume, portfólio e instrumento na interface ou no código, então inicie a estratégia.
- Observe o log da estratégia para mensagens como "Trading paused due to high news" ou "Next scheduled news" para confirmar a lógica de bloqueio.
A tradução para Python é intencionalmente omitida conforme solicitado.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using System.Globalization;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trade EA Template for News strategy converted from MQL.
/// </summary>
public class TradeEaTemplateForNewsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _useLowNews;
private readonly StrategyParam<int> _lowMinutesBefore;
private readonly StrategyParam<int> _lowMinutesAfter;
private readonly StrategyParam<bool> _useMediumNews;
private readonly StrategyParam<int> _mediumMinutesBefore;
private readonly StrategyParam<int> _mediumMinutesAfter;
private readonly StrategyParam<bool> _useHighNews;
private readonly StrategyParam<int> _highMinutesBefore;
private readonly StrategyParam<int> _highMinutesAfter;
private readonly StrategyParam<bool> _useNfpNews;
private readonly StrategyParam<int> _nfpMinutesBefore;
private readonly StrategyParam<int> _nfpMinutesAfter;
private readonly StrategyParam<bool> _onlySymbolNews;
private readonly StrategyParam<string> _newsEventsDefinition;
private readonly StrategyParam<int> _timeZoneOffsetHours;
private readonly StrategyParam<int> _takeProfitPoints;
private readonly StrategyParam<int> _stopLossPoints;
private readonly List<NewsEvent> _newsEvents = new();
private readonly HashSet<string> _instrumentCurrencies = new(StringComparer.OrdinalIgnoreCase);
private decimal? _previousOpenPrice;
private bool _newsBlocking;
private string _lastNewsMessage = string.Empty;
public TradeEaTemplateForNewsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame());
_useLowNews = Param(nameof(UseLowNews), true);
_lowMinutesBefore = Param(nameof(LowMinutesBefore), 15);
_lowMinutesAfter = Param(nameof(LowMinutesAfter), 15);
_useMediumNews = Param(nameof(UseMediumNews), true);
_mediumMinutesBefore = Param(nameof(MediumMinutesBefore), 30);
_mediumMinutesAfter = Param(nameof(MediumMinutesAfter), 30);
_useHighNews = Param(nameof(UseHighNews), true);
_highMinutesBefore = Param(nameof(HighMinutesBefore), 60);
_highMinutesAfter = Param(nameof(HighMinutesAfter), 60);
_useNfpNews = Param(nameof(UseNfpNews), true);
_nfpMinutesBefore = Param(nameof(NfpMinutesBefore), 180);
_nfpMinutesAfter = Param(nameof(NfpMinutesAfter), 180);
_onlySymbolNews = Param(nameof(OnlySymbolNews), true);
_newsEventsDefinition = Param(nameof(NewsEventsDefinition), string.Empty);
_timeZoneOffsetHours = Param(nameof(TimeZoneOffsetHours), 0);
_takeProfitPoints = Param(nameof(TakeProfitPoints), 100);
_stopLossPoints = Param(nameof(StopLossPoints), 100);
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public bool UseLowNews
{
get => _useLowNews.Value;
set => _useLowNews.Value = value;
}
public int LowMinutesBefore
{
get => _lowMinutesBefore.Value;
set => _lowMinutesBefore.Value = value;
}
public int LowMinutesAfter
{
get => _lowMinutesAfter.Value;
set => _lowMinutesAfter.Value = value;
}
public bool UseMediumNews
{
get => _useMediumNews.Value;
set => _useMediumNews.Value = value;
}
public int MediumMinutesBefore
{
get => _mediumMinutesBefore.Value;
set => _mediumMinutesBefore.Value = value;
}
public int MediumMinutesAfter
{
get => _mediumMinutesAfter.Value;
set => _mediumMinutesAfter.Value = value;
}
public bool UseHighNews
{
get => _useHighNews.Value;
set => _useHighNews.Value = value;
}
public int HighMinutesBefore
{
get => _highMinutesBefore.Value;
set => _highMinutesBefore.Value = value;
}
public int HighMinutesAfter
{
get => _highMinutesAfter.Value;
set => _highMinutesAfter.Value = value;
}
public bool UseNfpNews
{
get => _useNfpNews.Value;
set => _useNfpNews.Value = value;
}
public int NfpMinutesBefore
{
get => _nfpMinutesBefore.Value;
set => _nfpMinutesBefore.Value = value;
}
public int NfpMinutesAfter
{
get => _nfpMinutesAfter.Value;
set => _nfpMinutesAfter.Value = value;
}
public bool OnlySymbolNews
{
get => _onlySymbolNews.Value;
set => _onlySymbolNews.Value = value;
}
public string NewsEventsDefinition
{
get => _newsEventsDefinition.Value;
set => _newsEventsDefinition.Value = value;
}
public int TimeZoneOffsetHours
{
get => _timeZoneOffsetHours.Value;
set => _timeZoneOffsetHours.Value = value;
}
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
private bool HasNewsFilter => UseLowNews || UseMediumNews || UseHighNews || UseNfpNews;
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_previousOpenPrice = null;
_newsEvents.Clear();
_newsBlocking = false;
_lastNewsMessage = string.Empty;
_instrumentCurrencies.Clear();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
BuildInstrumentCurrencies();
ParseNewsEvents();
ConfigureProtection();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
}
private void ConfigureProtection()
{
// Configure stop-loss and take-profit to mirror the 100 point brackets from the template EA.
var step = Security?.PriceStep ?? 0m;
if (step <= 0m)
{
LogWarning("Security step is zero. Protective orders cannot be configured.");
return;
}
var takeUnit = TakeProfitPoints > 0 ? new Unit(step * TakeProfitPoints, UnitTypes.Absolute) : new Unit();
var stopUnit = StopLossPoints > 0 ? new Unit(step * StopLossPoints, UnitTypes.Absolute) : new Unit();
if (TakeProfitPoints > 0 || StopLossPoints > 0)
StartProtection(takeUnit, stopUnit);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
UpdateNewsState(candle.CloseTime);
// No bound indicators to check readiness for.
// Abort any signals while a news blackout is active.
if (_newsBlocking)
{
return;
}
if (_previousOpenPrice == null)
{
// Store the first open price so the next candle can compare against it.
_previousOpenPrice = candle.OpenPrice;
return;
}
var previousOpen = _previousOpenPrice.Value;
_previousOpenPrice = candle.OpenPrice;
if (Volume <= 0)
return;
if (Position != 0)
{
// The original template trades only when there are no existing positions.
return;
}
if (candle.ClosePrice > previousOpen)
{
BuyMarket();
LogInfo($"Long entry after bullish close at {candle.ClosePrice} compared to prior open {previousOpen}.");
}
else if (candle.ClosePrice < previousOpen)
{
SellMarket();
LogInfo($"Short entry after bearish close at {candle.ClosePrice} compared to prior open {previousOpen}.");
}
}
private void UpdateNewsState(DateTimeOffset currentTime)
{
// Without configured events the strategy should allow trading freely.
if (!HasNewsFilter || _newsEvents.Count == 0)
{
if (_newsBlocking)
{
_newsBlocking = false;
NotifyNewsMessage("No upcoming news events.");
}
return;
}
NewsEvent blockingEvent = null;
NewsEvent upcomingEvent = null;
for (var i = 0; i < _newsEvents.Count; i++)
{
var evt = _newsEvents[i];
if (!IsImportanceEnabled(evt.Importance))
continue;
if (!MatchesSecurity(evt))
continue;
if (IsInsideWindow(evt, currentTime))
{
if (blockingEvent == null || evt.Importance > blockingEvent.Importance)
blockingEvent = evt;
}
else if (evt.Time > currentTime)
{
if (upcomingEvent == null || evt.Time < upcomingEvent.Time)
upcomingEvent = evt;
}
}
var wasBlocking = _newsBlocking;
_newsBlocking = blockingEvent != null;
NotifyNewsMessage(BuildNewsMessage(blockingEvent, upcomingEvent));
if (_newsBlocking && !wasBlocking)
CancelActiveOrders();
}
private void NotifyNewsMessage(string message)
{
if (_lastNewsMessage.EqualsIgnoreCase(message))
return;
_lastNewsMessage = message;
LogInfo(message);
}
private bool IsImportanceEnabled(NewsImportances importance)
=> importance switch
{
NewsImportances.Low => UseLowNews,
NewsImportances.Medium => UseMediumNews,
NewsImportances.High => UseHighNews,
NewsImportances.Nfp => UseNfpNews,
_ => false
};
private bool IsInsideWindow(NewsEvent evt, DateTimeOffset currentTime)
{
var before = TimeSpan.FromMinutes(GetMinutesBefore(evt.Importance));
var after = TimeSpan.FromMinutes(GetMinutesAfter(evt.Importance));
var start = evt.Time - before;
var end = evt.Time + after;
return currentTime >= start && currentTime <= end;
}
private int GetMinutesBefore(NewsImportances importance)
=> importance switch
{
NewsImportances.Low => Math.Max(0, LowMinutesBefore),
NewsImportances.Medium => Math.Max(0, MediumMinutesBefore),
NewsImportances.High => Math.Max(0, HighMinutesBefore),
NewsImportances.Nfp => Math.Max(0, NfpMinutesBefore),
_ => 0
};
private int GetMinutesAfter(NewsImportances importance)
=> importance switch
{
NewsImportances.Low => Math.Max(0, LowMinutesAfter),
NewsImportances.Medium => Math.Max(0, MediumMinutesAfter),
NewsImportances.High => Math.Max(0, HighMinutesAfter),
NewsImportances.Nfp => Math.Max(0, NfpMinutesAfter),
_ => 0
};
private string BuildNewsMessage(NewsEvent activeEvent, NewsEvent upcomingEvent)
{
if (activeEvent != null)
{
var label = GetImportanceLabel(activeEvent.Importance);
var timeText = activeEvent.Time.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
var currencyPart = activeEvent.Currency.IsEmptyOrWhiteSpace() ? string.Empty : $" [{activeEvent.Currency}]";
var titlePart = activeEvent.Title.IsEmptyOrWhiteSpace() ? string.Empty : $" - {activeEvent.Title}";
return $"Trading paused due to {label} news{currencyPart} at {timeText}{titlePart}.";
}
if (upcomingEvent != null)
{
var label = GetImportanceLabel(upcomingEvent.Importance);
var timeText = upcomingEvent.Time.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
var currencyPart = upcomingEvent.Currency.IsEmptyOrWhiteSpace() ? string.Empty : $" [{upcomingEvent.Currency}]";
var titlePart = upcomingEvent.Title.IsEmptyOrWhiteSpace() ? string.Empty : $" - {upcomingEvent.Title}";
return $"Next scheduled news: {label}{currencyPart} at {timeText}{titlePart}.";
}
return "No upcoming news events.";
}
private static string GetImportanceLabel(NewsImportances importance)
=> importance switch
{
NewsImportances.Low => "low",
NewsImportances.Medium => "medium",
NewsImportances.High => "high",
NewsImportances.Nfp => "non-farm payroll",
_ => "unknown"
};
private void ParseNewsEvents()
{
// Parse the manual economic calendar description provided in the parameters.
_newsEvents.Clear();
var raw = NewsEventsDefinition;
if (raw.IsEmptyOrWhiteSpace())
{
LogInfo("News events list is empty. The filter will allow trading at all times.");
return;
}
var separators = new[] { ';', '\n', '\r' };
var entries = raw.Split(separators, StringSplitOptions.RemoveEmptyEntries);
for (var entryIndex = 0; entryIndex < entries.Length; entryIndex++)
{
var entry = entries[entryIndex].Trim();
if (entry.Length == 0)
continue;
var rawParts = entry.Split(',');
if (rawParts.Length < 3)
{
LogWarning($"Unable to parse news entry '{entry}'. Expected at least time, currency and importance.");
continue;
}
var parts = new string[rawParts.Length];
for (var i = 0; i < rawParts.Length; i++)
parts[i] = rawParts[i].Trim();
if (!DateTimeOffset.TryParse(parts[0], CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var time))
{
LogWarning($"Unable to parse time '{parts[0]}' in news entry '{entry}'.");
continue;
}
var currencies = parts[1].ToUpperInvariant();
if (!TryParseImportance(parts[2], out var importance))
{
LogWarning($"Unable to parse importance '{parts[2]}' in news entry '{entry}'.");
continue;
}
var title = string.Empty;
if (parts.Length > 3)
{
var count = parts.Length - 3;
var combined = string.Join(",", parts, 3, count);
title = combined.Trim();
}
time = time.ToOffset(TimeSpan.FromHours(TimeZoneOffsetHours));
_newsEvents.Add(new NewsEvent(time, currencies, importance, title));
}
_newsEvents.Sort((left, right) => left.Time.CompareTo(right.Time));
if (_newsEvents.Count > 0)
LogInfo($"Loaded {_newsEvents.Count} manual news event(s).");
else
LogInfo("No valid news events parsed. The filter will remain inactive.");
}
private static bool TryParseImportance(string value, out NewsImportances importance)
{
if (value.IsEmptyOrWhiteSpace())
{
importance = default;
return false;
}
var normalized = value.Trim();
if (normalized.Equals("LOW", StringComparison.OrdinalIgnoreCase))
{
importance = NewsImportances.Low;
return true;
}
if (normalized.Equals("MEDIUM", StringComparison.OrdinalIgnoreCase) ||
normalized.Equals("MID", StringComparison.OrdinalIgnoreCase) ||
normalized.Equals("MIDLE", StringComparison.OrdinalIgnoreCase) ||
normalized.Equals("MODERATE", StringComparison.OrdinalIgnoreCase))
{
importance = NewsImportances.Medium;
return true;
}
if (normalized.Equals("HIGH", StringComparison.OrdinalIgnoreCase))
{
importance = NewsImportances.High;
return true;
}
if (normalized.Equals("NFP", StringComparison.OrdinalIgnoreCase) ||
normalized.Contains("NONFARM", StringComparison.OrdinalIgnoreCase) ||
normalized.Contains("NON-FARM", StringComparison.OrdinalIgnoreCase))
{
importance = NewsImportances.Nfp;
return true;
}
importance = default;
return false;
}
private bool MatchesSecurity(NewsEvent evt)
{
if (!OnlySymbolNews)
return true;
// Match the configured currencies against the current instrument if required.
if (_instrumentCurrencies.Count == 0)
return true;
if (evt.Currency.IsEmptyOrWhiteSpace())
return true;
var separators = new[] { '/', ',', '|', ';', ' ' };
var tokens = evt.Currency.Split(separators, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < tokens.Length; i++)
{
var token = tokens[i].Trim();
if (token.Length == 0)
continue;
if (_instrumentCurrencies.Contains(token))
return true;
}
return false;
}
private void BuildInstrumentCurrencies()
{
// Extract major currency codes from the security symbol (e.g., EURUSD -> EUR, USD).
_instrumentCurrencies.Clear();
var code = Security?.Code;
if (code.IsEmptyOrWhiteSpace())
return;
var trimmed = code.Trim().ToUpperInvariant();
if (trimmed.Length >= 6)
{
_instrumentCurrencies.Add(trimmed.Substring(0, 3));
_instrumentCurrencies.Add(trimmed.Substring(trimmed.Length - 3, 3));
}
else
{
_instrumentCurrencies.Add(trimmed);
}
}
private sealed record class NewsEvent(DateTimeOffset Time, string Currency, NewsImportances Importance, string Title);
private enum NewsImportances
{
Low = 1,
Medium = 2,
High = 3,
Nfp = 4
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class trade_ea_template_for_news_strategy(Strategy):
"""News template EA: simple candle direction entries with SL/TP via StartProtection."""
def __init__(self):
super(trade_ea_template_for_news_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._take_profit_points = self.Param("TakeProfitPoints", 100) \
.SetDisplay("Take Profit Points", "TP distance in price steps", "Risk")
self._stop_loss_points = self.Param("StopLossPoints", 100) \
.SetDisplay("Stop Loss Points", "SL distance in price steps", "Risk")
self._previous_open_price = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def TakeProfitPoints(self):
return int(self._take_profit_points.Value)
@property
def StopLossPoints(self):
return int(self._stop_loss_points.Value)
def OnStarted2(self, time):
super(trade_ea_template_for_news_strategy, self).OnStarted2(time)
self._previous_open_price = None
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None and float(sec.PriceStep) > 0 else 0.0
if step > 0:
tp_unit = Unit(step * self.TakeProfitPoints, UnitTypes.Absolute) if self.TakeProfitPoints > 0 else None
sl_unit = Unit(step * self.StopLossPoints, UnitTypes.Absolute) if self.StopLossPoints > 0 else None
if tp_unit is not None and sl_unit is not None:
self.StartProtection(takeProfit=tp_unit, stopLoss=sl_unit)
elif tp_unit is not None:
self.StartProtection(takeProfit=tp_unit)
elif sl_unit is not None:
self.StartProtection(stopLoss=sl_unit)
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if self._previous_open_price is None:
self._previous_open_price = float(candle.OpenPrice)
return
previous_open = self._previous_open_price
self._previous_open_price = float(candle.OpenPrice)
if self.Position != 0:
return
close = float(candle.ClosePrice)
if close > previous_open:
self.BuyMarket()
elif close < previous_open:
self.SellMarket()
def OnReseted(self):
super(trade_ea_template_for_news_strategy, self).OnReseted()
self._previous_open_price = None
def CreateClone(self):
return trade_ea_template_for_news_strategy()