UTE/Strategy/Strategy.mqh
super.admin bd7e405a90 convert
2025-05-30 16:34:43 +02:00

879 lines
79 KiB
MQL5

//+------------------------------------------------------------------+
//| Strategy.mqh |
//| Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
//| https://www.mql5.com/ru/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link "https://www.mql5.com/ru/users/c-4"
#property strict
#define SOURCE ("ID " + (string)ExpertMagic() + " " + __FUNCTION__)
#include <Object.mqh>
#include "XML\XMLBase.mqh" // Работа с XML
#include "Logs.mqh" // Логирование
#ifdef __HT__
#include "Position.mqh"
#else
#include "PositionMT5.mqh" // Класс обыкновенных позиций
#endif
#include "TradeEnvironment.mqh" // Класс для детектирования изменений торгового окружения
#include "NewBarDetector.mqh" // Определитель нового бара
#include "NewTickDetector.mqh" // Определитель нового тика
#include "Series.mqh" // Предоставляет удобный доступ к OHLCV серии данных
#include "TradeControl.mqh" // Торговый модуль с дополнительными методами контроля за открытыми позициями
#include "TradeState.mqh" // Торговый модуль с дополнительными методами контроля за открытыми позициями
#include "MoneyManagment.mqh"
#include "PendingOrders.mqh"
#include "Symbol.mqh"
//+------------------------------------------------------------------+
//| Определяет тип рыночного события. |
//+------------------------------------------------------------------+
enum ENUM_MARKET_EVENT_TYPE
{
MARKET_EVENT_TICK, // Приход нового тика по текущему инструменту
MARKET_EVENT_BAR_OPEN, // Открытие нового бара по текущему инструменту
MARKET_EVENT_TIMER, // Срабатывание таймера
MARKET_EVENT_BOOK_EVENT // Изменение стакана (в т.ч. приход тика).
};
//+------------------------------------------------------------------+
//| Параметры события, которое повлекло вызов метода. |
//+------------------------------------------------------------------+
struct MarketEvent
{
ENUM_MARKET_EVENT_TYPE type; // Тип события.
ENUM_TIMEFRAMES period; // Период графика, к которому относится событие (только для MARKET_EVENT_BAR_OPEN).
string symbol; // Название инструмента, по которому произошло событие. Для всех событий, кроме
// MARKET_EVENT_BOOK_EVENT, название инструмента соответствует текущему инструменту.
};
//+------------------------------------------------------------------+
//| Основная статистика по открытым позициям стратегии (экземпляра) |
//+------------------------------------------------------------------+
struct PositionsStat
{
int open_buy; // Всего открытых позиций стратегии на покупку
int open_sell; // Всего открытых позиций стратегии на продажу
int open_total; // Общее количество открытых позиций стратегии
int open_complex; // Всего комплексных позиций, которые принадлежат данной стратегии
};
//+------------------------------------------------------------------+
//| Базовый класс стратегии-прослойки. |
//+------------------------------------------------------------------+
class CStrategy : public CObject
{
private:
MarketEvent m_event; // Последнее или текущее рыночное событие.
ulong m_last_changed; // Последнее время изменения торгового окружения в микросекундах с момента запуска.
uint m_expert_magic; // Уникальный идентификатор эксперта.
string m_expert_name; // Имя эксперта.
string m_expert_symbol; // Рабочий инструмент эксперта
ENUM_TIMEFRAMES m_timeframe; // Таймфрейм стратегии
ENUM_TRADE_STATE m_trade_state; // Торговое состояние эксперта.
CTradeEnvironment m_environment; // Торговое окружение портфеля.
CArrayObj m_bars_detectors; // Содержат определители новых баров.
CArrayObj m_ticks_detectors; // Содержит определители новых тиков.
void RebuildPositions(void);
void CallInit(const MarketEvent &event);
void CallSupport(const MarketEvent &event);
void SpyEnvironment(void);
virtual void ExitByStopRegim(CPosition *pos);
void NewBarsDetect(void);
void NewTickDetect(void);
void RecalcStatistic(PositionsStat &positions);
int LastWorkExpDay(MqlDateTime &dt);
protected:
bool m_multi_symbols;
CTradeState m_state; // Возвращает торговое состояние.
CArrayObj ActivePositions; // Список ОБЩИХ активных классических позиций.
CArrayObj ComplexPositions; // Список ОБЩИХ комплексных позиций состоящий из множества классических позиций
PositionsStat positions; // Статистика по позициям стратегии
CTradeControl Trade; // Торговый класс (сам CStrategy не обладает торговой логикой).
CArrayObj Modules; // Дополнительные модули сопровождения
static CLog* Log; // Логирование эксперта
string GetCurrentContract(string symbol);
bool CheckCurrentSL(double sl,ENUM_POSITION_TYPE type);
COrdersEnvironment PendingOrders;
/* Подписка на события "открытие нового бара" и "образование нового тика" */
bool AddBarOpenEvent(string symbol,ENUM_TIMEFRAMES timeframe);
bool AddTickEvent(string symbol);
void CheckVolumes(void);
/* Эксперт должен самостоятельно перестоить свои индикаторы при смене инструмента и таймфрейма,
для чего он должен отслеживать соответствующие события
*/
virtual void OnSymbolChanged(string symbol);
virtual void OnTimeframeChanged(ENUM_TIMEFRAMES tf);
/* Торговые функции, которые необходимо переопределить */
virtual void InitBuy(const MarketEvent &event);
virtual void InitSell(const MarketEvent &event);
virtual void InitComplexPos(const MarketEvent &event);
virtual void SupportBuy(const MarketEvent &event,CPosition *pos);
virtual void SupportSell(const MarketEvent &event,CPosition *pos);
virtual void SupportPendingBuy(const MarketEvent &event, CPendingOrder* order);
virtual void SupportPendingSell(const MarketEvent &event, CPendingOrder* order);
virtual void OnEvent(const MarketEvent& event);
virtual bool IsTrackEvents(const MarketEvent &event);
int PositionsTotal(ENUM_POSITION_TYPE pos_type, string symbol="", int magic = 0);
int OrdersTotal(ENUM_POSITION_TYPE pos_type, string symbol="", int magic = 0);
int OrdersTotal(ENUM_ORDER_TYPE order_type, string symbol="", int magic = 0);
public:
CMoneyManagment MM; // Модуль управления капиталом
CTrailing* Trailing; // Модуль управления трейлинг-стопом для всех позиций
CStrategy(void);
CStrategy(string symbol,string exp_name,uint magic,ENUM_TIMEFRAMES tf);
~CStrategy(void);
/*Общие свойства*/
static CStrategy *GetStrategy(string name);
CSymbol WS;
virtual bool ParseXmlParams(CXmlElement *params);
uint ExpertMagic(void);
void ExpertMagic(uint ExpertMagic);
string ExpertName(void);
void ExpertName(string name);
virtual string ExpertNameFull(void);
string ExpertSymbol();
void ExpertSymbol(string symbol);
void Timeframe(ENUM_TIMEFRAMES period);
ENUM_TIMEFRAMES Timeframe(void);
ENUM_TRADE_STATE TradeState(void);
void TradeState(ENUM_TRADE_STATE state);
/*Управление из вне*/
void Buy(double vol);
void Sell(double vol);
/*Передача событий*/
virtual bool OnInit(void);
void OnTick(void);
void OnTimer(void);
void OnBookEvent(string symbol);
virtual void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result){;}
virtual int Compare(const CObject *node,const int mode=0) const;
};
/*Размещение статических переменных*/
CLog *CStrategy::Log;
//+------------------------------------------------------------------+
//| Базовый класс стратегии-прослойки. |
//+------------------------------------------------------------------+
CStrategy::CStrategy(void)
{
m_multi_symbols = false;
m_last_changed = 0;
m_expert_magic = 0;
m_timeframe=PERIOD_CURRENT;
Log=CLog::GetLog();
WS.Name(Symbol());
WS.Period(Period());
}
//+------------------------------------------------------------------+
//| Базовый класс с обязательными параметрами. |
//+------------------------------------------------------------------+
CStrategy::CStrategy(string symbol,string exp_name,uint magic,ENUM_TIMEFRAMES tf) : WS(symbol, tf)
{
m_multi_symbols = false;
m_last_changed=0;
Log=CLog::GetLog();
ExpertSymbol(symbol);
ExpertName(exp_name);
Timeframe(tf);
ExpertMagic(magic);
}
//+------------------------------------------------------------------+
//| Диструктор. Удаляет модуль трейлинг-стопа в случае использования |
//+------------------------------------------------------------------+
CStrategy::~CStrategy(void)
{
if(CheckPointer(Trailing)!=POINTER_INVALID)
delete Trailing;
}
//+------------------------------------------------------------------+
//| Если рабочий символ изменился, эксперту необходимо самостоятельно|
//| перестроить свои индикаторы и другие внутренние данные на работу |
//| с этим символом, для чего переопределить данный обработчик |
//| изменения символа |
//+------------------------------------------------------------------+
void CStrategy::OnSymbolChanged(string symbol)
{
}
//+------------------------------------------------------------------+
//| Если рабочий таймфрейм изменился, эксперту необходимо |
//| самостоятельно перестроить свои индикаторы и другие внутренние |
//| данные на работу с этим таймфреймом, для чего переопределить |
//| данный обработчик изменения таймфрейма |
//+------------------------------------------------------------------+
void CStrategy::OnTimeframeChanged(ENUM_TIMEFRAMES tf)
{
}
//+------------------------------------------------------------------+
//| Переопределите метод правилами стратегии, при выполнении которых |
//| необходимо открыть ДЛИННУЮ позицию. Само открытие позиции также |
//| необходимо выполнить прямо в этом методе. |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//+------------------------------------------------------------------+
void CStrategy::InitBuy(const MarketEvent &event)
{
}
//+------------------------------------------------------------------+
//| Переопределите метод правилами стратегии, при выполнении которых |
//| необходимо открыть КОРОТКУЮ позицию. Само открытие позиции также |
//| необходимо выполнить прямо в этом методе. |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//+------------------------------------------------------------------+
void CStrategy::InitSell(const MarketEvent &event)
{
}
//+------------------------------------------------------------------+
//| Переопределите метод правилами стратегии, при выполнении которых |
//| необходимо открыть КОМПЛЕКСНУЮ (или арбитражную) позицию. |
//| Само открытие позиции также необходимо выполнить |
//| прямо в этом методе. |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//+------------------------------------------------------------------+
void CStrategy::InitComplexPos(const MarketEvent &event)
{
}
//+------------------------------------------------------------------+
//| Переопределите метод правилами стратегии, при выполнении которых |
//| необходимо закрыть ДЛИННУЮ позицию, переданную в качестве второго|
//| параметра. Само закрытие позиции также необходимо выполнить |
//| прямо в этом методе. |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//| pos - позиция, управление которой требуется произвести. |
//+------------------------------------------------------------------+
void CStrategy::SupportBuy(const MarketEvent &event,CPosition *pos)
{
}
//+------------------------------------------------------------------+
//| Переопределите метод правилами стратегии, при выполнении которых |
//| необходимо закрыть КОРОТКУЮ позицию,переданную в качестве второго|
//| параметра. Само закрытие позиции также необходимо выполнить |
//| прямо в этом методе. |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//| pos - позиция, управление которой требуется произвести. |
//+------------------------------------------------------------------+
void CStrategy::SupportSell(const MarketEvent &event,CPosition *pos)
{
}
//+------------------------------------------------------------------+
//| Переопределите данный метод для последовательного сопровождения |
//| отложенного ордера на покупку |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//| order - позиция, управление которой требуется произвести. |
//+------------------------------------------------------------------+
void CStrategy::SupportPendingBuy(const MarketEvent &event, CPendingOrder *order)
{
}
//+------------------------------------------------------------------+
//| Переопределите данный метод для последовательного сопровождения |
//| отложенного ордера на продажу |
//| IN: |
//| event - структура, описывающая событие, при получении |
//| которого произошел вызов этого метода. |
//| order - позиция, управление которой требуется произвести. |
//+------------------------------------------------------------------+
void CStrategy::SupportPendingSell(const MarketEvent &event, CPendingOrder *order)
{
}
//+------------------------------------------------------------------+
//| Общее событие OnEvent. Вызывается при получении любого события |
//| независимо от торгового режима и настроек эксперта. |
//+------------------------------------------------------------------+
void CStrategy::OnEvent(const MarketEvent &event)
{
}
//+------------------------------------------------------------------+
//| Отфильтровывает поступающие события. Если переданное событие |
//| не обрабатывается стратегией, возвращает ложь, если обрабатыва- |
//| ется - возвращает истину. |
//+------------------------------------------------------------------+
bool CStrategy::IsTrackEvents(const MarketEvent &event)
{
//Обрабатываем только открытие нового бара на рабочем инструменте и таймфрейме
if(event.type != MARKET_EVENT_BAR_OPEN)return false;
if(event.period != Timeframe())return false;
if(event.symbol != ExpertSymbol())return false;
return true;
}
//+------------------------------------------------------------------+
//| Делегирует дочерней стратегии парсинг ее специфических |
//| параметров, обнаруженных в секции <Params> |
//+------------------------------------------------------------------+
bool CStrategy::ParseXmlParams(CXmlElement *xmlParams)
{
string text="Found specific xml-settings, but "+ExpertName()+" strategy does not handle them. Override the method ParseXmlParams";
CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
Log.AddMessage(msg);
return false;
}
//+------------------------------------------------------------------+
//| Устанавливает уникальный идентфикатор эксперта. |
//+------------------------------------------------------------------+
void CStrategy::ExpertMagic(uint ExpertMagic)
{
m_expert_magic=ExpertMagic;
Trade.SetExpertMagicNumber(m_expert_magic);
}
//+------------------------------------------------------------------+
//| Возвращает уникальный идентификатор эксперта. |
//+------------------------------------------------------------------+
uint CStrategy::ExpertMagic(void)
{
return m_expert_magic;
}
//+------------------------------------------------------------------+
//| Возвращает Имя эксперта (имя эксперта должно быть предварительно |
//| установленно самим экспертом с помощью одноименного метода). |
//+------------------------------------------------------------------+
string CStrategy::ExpertName(void)
{
return m_expert_name;
}
//+------------------------------------------------------------------+
//| С помощью этого метода эксперт устанавливает свое имя. |
//+------------------------------------------------------------------+
void CStrategy::ExpertName(string name)
{
m_expert_name=name;
}
//+------------------------------------------------------------------+
//| Возвращает полное (уникальное имя эксперта). |
//| (Этот метод необходимо переопределить в производном классе) |
//+------------------------------------------------------------------+
string CStrategy::ExpertNameFull(void)
{
return ExpertName();
}
//+------------------------------------------------------------------+
//| Возвращает рабочий инструмент эксперта. |
//+------------------------------------------------------------------+
string CStrategy::ExpertSymbol(void)
{
if(m_expert_symbol==NULL || m_expert_symbol=="")
return _Symbol;
return m_expert_symbol;
}
//+------------------------------------------------------------------+
//| Устанавливает рабочий инструмент эксперта. |
//+------------------------------------------------------------------+
void CStrategy::ExpertSymbol(string symbol)
{
m_expert_symbol=GetCurrentContract(symbol);
OnSymbolChanged(m_expert_symbol);
WS.Name(symbol);
}
//+------------------------------------------------------------------+
//| Вызывается менеджером стратегий при наступлении системного |
//| события 'новый тик'. |
//+------------------------------------------------------------------+
void CStrategy::OnTick(void)
{
NewTickDetect();
NewBarsDetect();
}
//+------------------------------------------------------------------+
//| Это событие вызывается при добавлении стратегии в список |
//| стратегий. Подразумевается, что в момент вызова этой функции, |
//| все базовые параметры эксперта, такие как название симовола, |
//| магический номер и тайфрем будут установлены. И эксперт сможет |
//| сконфигурировать в этом методе свои внутренние данные. |
//| В случае, если OnInit стратегии вернет false, стратегия не будет |
//| добавлена в список. |
//+------------------------------------------------------------------+
bool CStrategy::OnInit(void)
{
return true;
}
//+------------------------------------------------------------------+
//| Вызывается менеджером стратегий при наступлении системного |
//| события 'OnTimer'. |
//+------------------------------------------------------------------+
void CStrategy::OnTimer(void)
{
m_event.symbol=Symbol();
m_event.type=MARKET_EVENT_TIMER;
m_event.period=(ENUM_TIMEFRAMES)Period();
OnEvent(m_event);
CallSupport(m_event);
CallInit(m_event);
NewTickDetect();
NewBarsDetect();
}
//+------------------------------------------------------------------+
//| Вызывается менеджером стратегий при наступлении системного |
//| события 'OnBookEvent'. |
//+------------------------------------------------------------------+
void CStrategy::OnBookEvent(string symbol)
{
m_event.symbol=symbol;
m_event.type=MARKET_EVENT_BOOK_EVENT;
m_event.period=PERIOD_CURRENT;
OnEvent(m_event);
CallSupport(m_event);
CallInit(m_event);
NewTickDetect();
NewBarsDetect();
}
//+------------------------------------------------------------------+
//| Покупает от имени эксперта объем vol |
//+------------------------------------------------------------------+
void CStrategy::Buy(double vol)
{
Trade.Buy(vol,ExpertSymbol(),"hand buy");
}
//+------------------------------------------------------------------+
//| Продаем от имени эксперта объем vol |
//+------------------------------------------------------------------+
void CStrategy::Sell(double vol)
{
Trade.Sell(vol,ExpertSymbol(),"hand sell");
}
//+------------------------------------------------------------------+
//| Возвращает текущее торговое состояние эксперта. |
//+------------------------------------------------------------------+
ENUM_TRADE_STATE CStrategy::TradeState(void)
{
return m_trade_state;
}
//+------------------------------------------------------------------+
//| Устанавливает текущее торговое состояние эксперта. |
//+------------------------------------------------------------------+
void CStrategy::TradeState(ENUM_TRADE_STATE state)
{
if(state!=m_state.GetTradeState())
{
m_state.SetTradeState(D'00:00', D'23:59', ALL_DAYS_OF_WEEK, state);
string text="The mode of the current strategy has been changed to "+EnumToString(m_state.GetTradeState())+
". The changes will come into force at receipt of new events";
CMessage *msg=new CMessage(MESSAGE_INFO,SOURCE,text);
Log.AddMessage(msg);
}
}
//+------------------------------------------------------------------+
//| Вызывает логику открытия позиции при условии, что торговое |
//| состояние явно не запрещает этого делать. |
//+------------------------------------------------------------------+
void CStrategy::CallInit(const MarketEvent &event)
{
m_trade_state=m_state.GetTradeState();
if(m_trade_state == TRADE_STOP)return;
if(m_trade_state == TRADE_WAIT)return;
if(m_trade_state == TRADE_NO_NEW_ENTRY)return;
SpyEnvironment();
InitComplexPos(event);
if(m_trade_state==TRADE_BUY_AND_SELL || m_trade_state==TRADE_BUY_ONLY)
InitBuy(event);
if(m_trade_state==TRADE_BUY_AND_SELL || m_trade_state==TRADE_SELL_ONLY)
InitSell(event);
}
//+------------------------------------------------------------------+
//| Вызывает логику сопровождения позиций при условии, что торговое |
//| состояние не равно TRADE_WAIT. |
//+------------------------------------------------------------------+
void CStrategy::CallSupport(const MarketEvent &event)
{
m_trade_state=m_state.GetTradeState();
if(m_trade_state == TRADE_WAIT)return;
SpyEnvironment();
// Управление активными позициями
for(int i=ActivePositions.Total()-1; i>=0; i--)
{
CPosition *pos=ActivePositions.At(i);
if(pos.ExpertMagic()!=m_expert_magic)continue;
if(!m_multi_symbols && pos.Symbol()!=ExpertSymbol())continue;
if(CheckPointer(Trailing)!=POINTER_INVALID)
{
if(CheckPointer(pos.Trailing)==POINTER_INVALID)
{
pos.Trailing = Trailing.Copy();
pos.Trailing.SetPosition(pos);
}
pos.Trailing.Modify();
if(!pos.IsActive())
continue;
}
if(pos.Direction()==POSITION_TYPE_BUY)
SupportBuy(event,pos);
else
SupportSell(event,pos);
if(m_trade_state==TRADE_STOP && pos.IsActive())
ExitByStopRegim(pos);
}
// Удаление отложенных ордеров при смене режима
if(PendingOrders.Total() > 0 && (m_trade_state == TRADE_STOP ||
m_trade_state == TRADE_BUY_ONLY || m_trade_state == TRADE_SELL_ONLY))
{
for(int p = PendingOrders.Total()-1; p >= 0; p--)
{
CPendingOrder* pend = PendingOrders.GetOrder(p);
if(!pend.IsMain(ExpertSymbol(), ExpertMagic()))continue;
bool needDelete = m_trade_state == TRADE_STOP;
// SELL_ONLY - удаляем отложенные ордера на покупку
if(!needDelete)
{
needDelete = m_trade_state == TRADE_SELL_ONLY &&
(pend.Type() == ORDER_TYPE_BUY_STOP ||
pend.Type() == ORDER_TYPE_BUY_LIMIT);
}
// BUY_ONLY - удаляем отложенные ордера на продажу
if(!needDelete)
{
needDelete = m_trade_state == TRADE_BUY_ONLY &&
(pend.Type() == ORDER_TYPE_SELL_STOP ||
pend.Type() == ORDER_TYPE_SELL_LIMIT);
}
if(needDelete)
pend.Delete();
}
}
for(int i = PendingOrders.Total()-1; i >= 0; i--)
{
CPendingOrder* order = PendingOrders.GetOrder(i);
if(order.ExpertMagic()!=m_expert_magic)continue;
if(order.Direction() == POSITION_TYPE_BUY)
SupportPendingBuy(event, order);
else
SupportPendingSell(event, order);
}
}
//+------------------------------------------------------------------+
//| Отслеживает изменение торгового окружения. |
//+------------------------------------------------------------------+
void CStrategy::SpyEnvironment(void)
{
if(m_environment.ChangeEnvironment())
{
//printf(ExpertNameFull()+". Trading environment has changed. Rebuild the environment");
RebuildPositions();
RecalcStatistic(positions);
m_environment.RememberEnvironment();
}
}
//+------------------------------------------------------------------+
//| Пересчитывает статистику позиций и заполняет соответствующую |
//| структуру. |
//+------------------------------------------------------------------+
void CStrategy::RecalcStatistic(PositionsStat &pos)
{
pos.open_buy=0;
pos.open_sell=0;
pos.open_total=0;
pos.open_complex=0;
for(int i=0; i<ActivePositions.Total(); i++)
{
CPosition *cpos=ActivePositions.At(i);
if(cpos.ExpertMagic()!=ExpertMagic())continue;
if(cpos.Symbol() != ExpertSymbol())continue;
pos.open_total+=1;
if(cpos.Direction()==POSITION_TYPE_BUY)
pos.open_buy++;
else
pos.open_sell++;
}
}
//+------------------------------------------------------------------+
//| Перестраивает списки позиций. |
//+------------------------------------------------------------------+
#ifdef __HT__
void CStrategy::RebuildPositions(void)
{
ActivePositions.Clear();
for(int i = 0; i < TransactionsTotal(); i++)
{
if(!TransactionSelect(i))continue;
if(TransactionType() != TRANS_HEDGE_POSITION)continue;
CPosition* pos = new CPosition();
ActivePositions.Add(pos);
}
}
#else
void CStrategy::RebuildPositions(void)
{
ActivePositions.Clear();
ENUM_ACCOUNT_MARGIN_MODE mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
if(mode!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
for(int i=0; i<PositionsTotal(); i++)
{
string symbol=PositionGetSymbol(i);
PositionSelect(symbol);
CPosition *pos=new CPosition();
ActivePositions.Add(pos);
}
}
else
{
for(int i=0; i<PositionsTotal(); i++)
{
ulong ticket=PositionGetTicket(i);
PositionSelectByTicket(ticket);
CPosition *pos=new CPosition();
ActivePositions.Add(pos);
}
}
}
#endif
//+------------------------------------------------------------------+
//| Устанавливает рабочий таймфрем стратегии. |
//+------------------------------------------------------------------+
void CStrategy::Timeframe(ENUM_TIMEFRAMES period)
{
m_timeframe=period;
OnTimeframeChanged(m_timeframe);
WS.Period(period);
}
//+------------------------------------------------------------------+
//| Возвращает рабочий таймфрейм стратегии. |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES CStrategy::Timeframe(void)
{
return m_timeframe;
}
//+------------------------------------------------------------------+
//| Закрывает позицию по режиму Stop. |
//+------------------------------------------------------------------+
void CStrategy::ExitByStopRegim(CPosition *pos)
{
ResetLastError();
CMessage *msg_info=new CMessage(MESSAGE_INFO,ExpertName(),"Try close position #"+(string)pos.ID()+" by stop regim...");
Log.AddMessage(msg_info);
bool res=pos.CloseAtMarket("Exit by StopRegim");
if(res)
CMessage *msg=new CMessage(MESSAGE_INFO,ExpertName(),"Out of position #"+(string)pos.ID()+" successfully completed.");
//Если закрытие позиции не удалось, то об этом напишет сам метод pos.CloseAtMarket.
}
//+------------------------------------------------------------------+
//| Определяет наступление новых баров и генерирует соответствующее |
//| событие для эксперта. |
//+------------------------------------------------------------------+
void CStrategy::NewBarsDetect(void)
{
if(m_bars_detectors.Total()==0)
AddBarOpenEvent(ExpertSymbol(),Timeframe());
for(int i=0; i<m_bars_detectors.Total(); i++)
{
CBarDetector *bar=m_bars_detectors.At(i);
if(bar.IsNewBar())
{
m_event.period = bar.Timeframe();
m_event.symbol = bar.Symbol();
m_event.type=MARKET_EVENT_BAR_OPEN;
SpyEnvironment();
OnEvent(m_event);
CallSupport(m_event);
CallInit(m_event);
}
}
}
//+------------------------------------------------------------------+
//| Детектирует появление новых тиков на мультиинструментах. |
//+------------------------------------------------------------------+
void CStrategy::NewTickDetect(void)
{
if(m_ticks_detectors.Total()==0)
AddTickEvent(ExpertSymbol());
for(int i=0; i<m_ticks_detectors.Total(); i++)
{
CTickDetector *tick=m_ticks_detectors.At(i);
if(tick.IsNewTick())
{
m_event.period=PERIOD_CURRENT;
m_event.type=MARKET_EVENT_TICK;
m_event.symbol=tick.Symbol();
SpyEnvironment();
OnEvent(m_event);
CallSupport(m_event);
CallInit(m_event);
}
}
}
//+------------------------------------------------------------------+
//| Подписывает эксперта на получение события открытия нового бара |
//| по инструменту symbol и таймфрейму timframe. Если эксперт уже |
//| подписан на данное событие, метод вернет ложь. Если подписка |
//| прошла успешно, возвращается истина. |
//+------------------------------------------------------------------+
bool CStrategy::AddBarOpenEvent(string symbol,ENUM_TIMEFRAMES timeframe)
{
for(int i=0; i<m_bars_detectors.Total(); i++)
{
CBarDetector *d=m_bars_detectors.At(i);
if(d.Symbol()==symbol && d.Timeframe()==timeframe)
{
string text="You are already subscribed to the opening bars of said symbol and timeframe.";
CMessage *message=new CMessage(MESSAGE_INFO,__FUNCTION__,text);
return false;
}
}
datetime time[];
if(CopyTime(symbol,timeframe,0,3,time)==0)
{
string text="A symbol "+symbol+" that you want to monitor is not available in the terminal."+
" Make sure that the name of the instrument and its timeframe"+EnumToString(timeframe)+" are correct.";
CMessage *message=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
return false;
}
CBarDetector *bar=new CBarDetector(symbol,timeframe);
return m_bars_detectors.Add(bar);
}
//+------------------------------------------------------------------+
//| Подписывает эксперта на получение события "новый тик", |
//| по инструменту symbol. Если эксперт уже подписан на данное |
//| событие, метод вернет ложь. Если подписка |
//| прошла успешно, возвращается истина. |
//+------------------------------------------------------------------+
bool CStrategy::AddTickEvent(string symbol)
{
for(int i=0; i<m_ticks_detectors.Total(); i++)
{
CTickDetector *d=m_ticks_detectors.At(i);
if(d.Symbol()==symbol)
{
string text="You are already subscribed to new tick event of said symbol.";
CMessage *message=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
return false;
}
}
datetime time[];
if(CopyTime(symbol,PERIOD_D1,0,3,time)==0)
{
string text="A symbol "+symbol+" that you want to monitor is not available in the terminal."+
" Make sure that the name of the instrument are correct.";
CMessage *message=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
return false;
}
CTickDetector *tick=new CTickDetector(symbol);
return m_ticks_detectors.Add(tick);
}
//+------------------------------------------------------------------+
//| Возвращает полное имя текущего контракта для FORTS, которое |
//| соответствует переданному символу. Например, если текущая дата |
//| равна 02.10.2015, а переданный символ равен "Si", метод вернет |
//| название ближайшего контракта: Si-12.15. |
//| Перед возратом имени инструмента проверяется его фактическая |
//| доступность для торговли, и если он недоступен, возвращается |
//| NULL. В противном случае возвращается полное название контракта. |
//+------------------------------------------------------------------+
string CStrategy::GetCurrentContract(string symbol)
{
datetime time[];
if(SymbolInfoInteger(symbol,SYMBOL_SELECT))
return symbol;
MqlDateTime dt={0};
TimeCurrent(dt);
int mon=0;
int year=0;
if((dt.mon==12 && dt.day>=14) || dt.mon==1 || dt.mon==2 || (dt.mon==3 && dt.day<14))
{
mon=3;
year=dt.year+1;
}
if((dt.mon==3 && dt.day>=14) || dt.mon==4 || dt.mon==5 || (dt.mon==6 && dt.day<14))
{
mon=6;
year=dt.year;
}
if((dt.mon==6 && dt.day>=14) || dt.mon==7 || dt.mon==8 || (dt.mon==9 && dt.day<14))
{
mon=9;
year=dt.year;
}
if((dt.mon==9 && dt.day>=14) || dt.mon==10 || dt.mon==11 || (dt.mon==12 && dt.day<14))
{
mon=12;
year=dt.year;
}
if(mon==0 || year==0)
{
string text="The current date is outside the execution of futures";
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
return NULL;
}
//Пробуем сгенерировать инструмент и получить по нему данные
string full_symbol=symbol+"-"+(string)mon+"."+StringSubstr((string)year,2);
if(!SymbolInfoInteger(full_symbol,SYMBOL_SELECT))
{
string text="Symbol "+symbol+" is not not selected in market watch. Check the name of the instrument";
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
Log.AddMessage(msg);
return NULL;
}
return full_symbol;
}
//+------------------------------------------------------------------+
//| Переопределяет сравнение по маджику |
//+------------------------------------------------------------------+
int CStrategy::Compare(const CObject *obj,const int mode=0)const
{
const CStrategy *str=obj;
if(m_expert_magic > str.m_expert_magic)return 1;
if(m_expert_magic < str.m_expert_magic)return -1;
return 0;
}
//+------------------------------------------------------------------+
//| Возвращает общее количество позиций по заданному критерию |
//+------------------------------------------------------------------+
int CStrategy::PositionsTotal(ENUM_POSITION_TYPE pos_type, string symbol="", int magic = 0)
{
int total = 0;
for(int i = 0; i < ActivePositions.Total(); i++)
{
CPosition* pos = ActivePositions.At(i);
if(magic != 0 && magic != pos.ExpertMagic())continue;
if(symbol != "" && symbol != pos.Symbol())continue;
if(pos.Direction() != pos_type)continue;
total++;
}
return total;
}
//+------------------------------------------------------------------+
//| Возвращает общее количество отложенных ордеров, чье направление |
//| равно заданному |
//+------------------------------------------------------------------+
int CStrategy::OrdersTotal(ENUM_POSITION_TYPE pos_type, string symbol="", int magic = 0)
{
int total = 0;
for(int i = 0; i < PendingOrders.Total(); i++)
{
CPendingOrder* order = PendingOrders.GetOrder(i);
if(magic != 0 && magic != order.ExpertMagic())continue;
if(symbol != "" && symbol != order.Symbol())continue;
if(order.Direction() != pos_type)continue;
total++;
}
return total;
}
//+------------------------------------------------------------------+
//| Возвращает общее количество отложенных ордеров, чей тип |
//| равен заданному |
//+------------------------------------------------------------------+
int CStrategy::OrdersTotal(ENUM_ORDER_TYPE order_type, string symbol="", int magic = 0)
{
int total = 0;
for(int i = 0; i < PendingOrders.Total(); i++)
{
CPendingOrder* order = PendingOrders.GetOrder(i);
if(magic != 0 && magic != order.ExpertMagic())continue;
if(symbol != "" && symbol != order.Symbol())continue;
if(order.Type() != order_type)continue;
total++;
}
return total;
}
#include "StrategiesList.mqh"
//+------------------------------------------------------------------+