879 lines
79 KiB
MQL5
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"
|
|
//+------------------------------------------------------------------+
|