Основной цикл советников
Основная задача любого советника ставить ордера. Но не просто ставить, а ставить, дожидаясь выполнения определенных условий, соблюдая мани менеджмент и проч. Кроме того, советник должен управлять выставленными ордерами. Например, в логику советника может быть заложено правило, содержащее запрет многократного выставления ордеров в ответ на единственный сигнал, сопровождение рыночных ордеров тралом, удаление “лишних” отложенных ордеров.
Поэтому советник вынужден постоянно мониторить рынок, проверяя наличие ордеров, сортируя их, выбирая те, которые интересуют данного советника. Такая выборка может происходить по мэджику, по валютной паре, на которой советник работает.
Кроме того попутно советник может собирать определенную статистику.
Для выполнения этих задач в коде советника организуется цикл перебора всех ордеров и выполнения определенных действий над ними. Этот цикл выполняется при каждом тике, а его код остается, в основном, неизменным. Поэтому вполне логично выделить этот код в класс:
class CSnapData {
public:
void CSnapData() {
dSwpComm = -1;
dAverageB = -1;
dAverageS = -1;
Reset();
}
virtual void ~CSnapData(){}
int iCountB; // Количество ордеров на покупку
int iCountS; // ... на продажу
int iCountBL; //... лимитников на покупку
int iCountSL; //... лимитников на продажу
int iCountBS; //... стоповых на покупку
int iCountSS; //... стоповых на продажу
double dLotB; // суммарный лот на покупку
double dLotS; //... на продажу
double dLotBL; //... лимитников на покупку
double dLotSL; //... лимитников на продажу
double dLotBS; //... стоповых на покупку
double dLotSS; //... стоповых на продажу
double dAverageB; // средневзвешенная цена на покупку
double dAverageS; // средневзвешенная цена на продажу
double dBuyParam; // Служебные параметры
double dSellParam; // Служебные параметры
double dDrDown; // Текущая просадка
double dSwpComm; //Накопленные комиссии и свопы
void Reset () {
dLotB = 0;
dLotBL = 0;
dLotBS = 0;
dLotS = 0;
dLotSL = 0;
dLotSS = 0;
dDrDown = 0;
iCountB = 0;
iCountBL = 0;
iCountBS = 0;
iCountS = 0;
iCountSL = 0;
iCountSS = 0;
}
};
class CMarketSnap {
public:
void CMarketSnap() {smb = NULL; mgk = -1; bIsDirty = false;}
void CMarketSnap(string symbol, int magic = -1) {smb = symbol; mgk = magic; bIsDirty = false;}
virtual void ~CMarketSnap() {}
void CreateSnap() {bIsDirty = UpdateSnap(SnapData);}
const bool IsDirty() const {return (bIsDirty);}
CSnapData* GetSnap() {return (GetPointer(SnapData));}
protected:
bool UpdateSnap(CSnapData& Snap);
virtual void OnBuyFind (int ticket, double price, double lot) {}
virtual void OnBuySFind (int ticket, double price, double lot) {}
virtual void OnBuyLFind (int ticket, double price, double lot) {}
virtual void OnSellFind (int ticket, double price, double lot) {}
virtual void OnSellSFind(int ticket, double price, double lot) {}
virtual void OnSellLFind(int ticket, double price, double lot) {}
CSnapData SnapData;
bool bIsDirty;
private:
string smb;
int mgk;
};
bool CMarketSnap::UpdateSnap (CSnapData& Snap) {
Snap.Reset();
int total = OrdersTotal();
int type;
bool res;
double l, p;
Snap.dBuyParam = 0; Snap.dSellParam = 0;
for (int i = 0; i < total; i++) {
if ( OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) {
if (smb == NULL || OrderSymbol() == smb) {
if (mgk < 0 || OrderMagicNumber() == mgk) {
type = OrderType();
l = OrderLots();
p = OrderOpenPrice();
switch (type) {
case OP_BUY :
Snap.iCountB++;
Snap.dLotB += l;
Snap.dDrDown += OrderProfit();
Snap.dSwpComm += OrderCommission() + OrderSwap();
Snap.dBuyParam += l * p;
OnBuyFind(OrderTicket(), p, l);
break;
case OP_SELL :
Snap.iCountS++;
Snap.dLotS += l;
Snap.dDrDown += OrderProfit();
Snap.dSwpComm += OrderCommission() + OrderSwap();
Snap.dSellParam += l * p;
OnSellFind(OrderTicket(), p, l);
break;
case OP_BUYLIMIT :
Snap.iCountBL++;
Snap.dLotBL += l;
OnBuyLFind(OrderTicket(), p, l);
break;
case OP_SELLLIMIT :
Snap.iCountSL++;
Snap.dLotSL += l;
OnSellLFind(OrderTicket(), p, l);
break;
case OP_BUYSTOP :
Snap.iCountBS++;
Snap.dLotBS += l;
OnBuySFind(OrderTicket(), p, l);
break;
case OP_SELLSTOP :
Snap.iCountSS++;
Snap.dLotSS += l;
OnSellSFind(OrderTicket(), p, l);
break;
default:
continue;
}//switch (type)
}
}//if (OrderSymbol() == smb && smb == NULL)
}//if ( OrderSelect(i,SELECT_BY_POS,MODE_TRADES)
}//for (int i = 0; i < total; i++)
double l1, l2;
l1 = (Snap.iCountB == 0)? 0: ND(Snap.dBuyParam / Snap.dLotB);
l2 = (Snap.iCountS == 0)? 0: ND(Snap.dSellParam / Snap.dLotS);
if ( (Snap.dAverageB != -1 && Snap.dAverageB != l1) ||
(Snap.dAverageS != -1 && Snap.dAverageS != l2) ) res = true;
else res = false;
Snap.dAverageB = l1;
Snap.dAverageS = l2;
return (res);
}
Затем, в коде рабочего советника нужно создать класс, унаследовав его от CMarketSnap. В коде Вашего класса следует переопределить виртуальные методы OnBuyFind, или другие, интересующие Вас. Далее, тем, или иным способом вызывается метод CreateSnap() базового класса CMarketSnap. При каждом вызове будет выполняться перебор всех имеющихся ордеров с вызовом переопределенных виртуальных функций. Попутно будут заполняться поля встроенного объекта типа CSnapData, содержащего интересную и полезную статистику. Указатель на этот объект возвращает метод GetSnap().Получившаяся итоговая картина сравнивается с предыдущей и если обнаруживаются изменения (например закрылся ордер), то флаг bIsDirty выставляется в true. Состояние этго флага возвращает метод IsDirty().