Параметры под центовый счёт алпари. Пара евро-бакс. Параметров много, некоторые взаимоисключающие. Конструктивные замечания по коду с удовольствием рассмотрю.
Тег «коде» не обеспечивает нормальный моноширинный шрифт. Пробелы проседают. Минус заводчикам.
/***************************************************************************************************
* Copyright 2014, zoolook@netfram.com *
* http://www.netfram.com *
***************************************************************************************************/
#property copyright "zoolook@netfram.com"
#property link "http://www.netfram.com"
#define version "sar02mod7b"
//+------------------------------------------------------------------------------------------------+
extern double BaseLot = 0.01; // начальный/минимальный лот
extern double MaxiLot = 10.0; // максимально допустимый лот
extern double LotExp = 1.7; // мартингейл
extern bool EquLot = false; // lot_buy = lot_sell, актуален только для LotExp > 1
extern int DynamicLot = 1; // 0=BaseLot, 1=FreeMargin, 2=Equity, 3=Balance
extern double RiskFactor = 0.0001; // риск от средств счёта для динамического лота
extern int RaisePct = 0; // процент доливки по тренду от объема позиций (0 = нет доливки)
extern bool RaiseAll = false; // игнорировать убыточные позиции при доливке
//+------------------------------------------------------------------------------------------------+
extern int TakeProfit = 263; // финальная прибыль в пунктах для всех ордеров серии (0 = нет)
extern int StopProfit = 114; // мин. прибыль в пунктах для начала трейлинга (0 = нет трейла)
extern int Trailing = 7; // дистанция трейлинг-стопа до Bid/Ask
//+------------------------------------------------------------------------------------------------+
extern int PipStep = 1; // базовая дистанция между ордерами
extern double PipExp = 1.0; // приращение дистанции в серии
extern bool DynamicPips = false; // динамический расчёт дистанции на истории
extern int DynPipTF = 240; // таймфрейм истории для динамики
extern int DynPipBars = 4; // глубина истории для динамики
extern double DynPipCo = 2.0; // множитель|делитель для динамики
//+------------------------------------------------------------------------------------------------+
extern bool ClOverInner = true; // закрывать перекрытые ордера внутренние или внешние
extern int ClOverPips = 15; // закрывать перекрытые ордера с заданной дельтой
extern int ClOverDay = 5; // пятница > для отключения данного функционала <
extern int ClOverHour = 22; // 23 часа > достаточно поставить несуществующий <
extern int ClOverMinute = 50; // 59 минут > день недели или время <
//+------------------------------------------------------------------------------------------------+
extern bool BarsOnly = false; // работа только на новых барах
extern bool AllOrders = false; // все ордера, игнор Magic
extern bool AutoStop = true; // false = только с явно заданным стопом
//+------------------------------------------------------------------------------------------------+
extern double OrderAccel = 0.047; // ускорение SAR для отложников
extern int OrderShift = 0; // сдвиг SAR для отложников
extern double TrailAccel = 0.13; // ускорение SAR для трейлинг-стопа
extern int TrailShift = 0; // сдвиг SAR для трейлинг-стопа
//+------------------------------------------------------------------------------------------------+
extern int MaxTickets = 9; // максимальное число ордеров в серии
extern int Slippage = 3; // допустимое проскальзывание при входе с рынка
extern int GlobalTF = 5; // актуальный таймфрейм пары (0 = работа по текущему TF графика)
extern int TrailTF = 5; // таймфрейм трейлинга стопов по SAR (0 = по текущему)
//+------------------------------------------------------------------------------------------------+
extern bool ShowAvg = true; // показывать уровни усреднений, тейков и объемы
extern color cMPB = DodgerBlue; // цвет средневзвешенного buy
extern color cMPS = DeepPink; // цвет средневзвешенного sell
//+------------------------------------------------------------------------------------------------+
extern int Magic = 20150305; // уникальный ИД ордеров
//+------------------------------------------------------------------------------------------------+
static double MinLot; // минимальный лот на рынке
static int LotDec; // количество знаков после запятой для Lot
static int Spread; // спрэд в пунктах
//+------------------------------------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------------------------------------+
int init()
{
MinLot = MarketInfo(Symbol(), MODE_MINLOT);
LotDec = log10(1 / MarketInfo(Symbol(), MODE_LOTSTEP));
Spread = MarketInfo(Symbol(), MODE_SPREAD);
Print("");
Print("-----------------------------------");
if (MinLot > BaseLot)
{
Print("!!!! WARNING: setting 'BaseLot' = ", MinLot);
Print("!!!! WARNING: 'BaseLot' less than market minimal lot");
BaseLot = MinLot;
}
Print("LotDecimal: ", LotDec);
Print(" MinLot: ", MinLot);
Print(" Spread: ", Spread);
Print(" Point: ", DTS(Point));
Print(" Digits: ", Digits);
Print("---------- ", version, " ----------");
Print("");
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
draw_median(0, 0, 0, 0, 0);
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
static bool DoRecalcBuy = true; // требуется пересчет тейков бычьей серии
static bool DoRecalcSell = true; // требуется пересчет тейков медвежьей серии
static double old_median_buy = 0;
static double old_median_sell = 0;
static datetime last_global_tf = 0;
static datetime last_trailing_tf = 0;
// закрываем перекрытые ордера в конце торговой недели
if(DayOfWeek() == ClOverDay && Hour() >= ClOverHour && Minute() >= ClOverMinute)
{
close_overlapped(ClOverPips); /* ВНИМАНИЕ!!!: вызывается на каждый тик! доработать! */
return (0);
}
if (BarsOnly == false || new_bar(last_trailing_tf, TrailTF)) traileraiser();
double median_buy = price_median(OP_BUY);
double median_sell = price_median(OP_SELL);
if (ShowAvg)
{
double vol_buy = get_volume(OP_BUY);
double vol_sell = get_volume(OP_SELL);
Comment("-- Volume --", "\n Buy: ", DTS(vol_buy, LotDec), "\n Sell: ", DTS(vol_sell, LotDec));
draw_median(median_buy, vol_buy, median_sell, vol_sell/*, realtp*/);
}
if (median_buy != old_median_buy) { old_median_buy = median_buy ; DoRecalcBuy = true; }
if (median_sell != old_median_sell) { old_median_sell = median_sell ; DoRecalcSell = true; }
int i;
double realtp = (TakeProfit + Spread) * Point;
if (DoRecalcBuy == true && median_buy > 0)
{
DoRecalcBuy = false;
for (i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i) && OrderType() == OP_BUY)
DoRecalcBuy |= (order_mod(0 /* price */, 0 /* SL */, median_buy + realtp) != 0);
} else DoRecalcBuy = false;
if (DoRecalcSell == true && median_sell > 0)
{
DoRecalcSell = false;
for (i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i) && OrderType() == OP_SELL)
DoRecalcSell |= (order_mod(0 /* price */, 0 /* SL */, median_sell - realtp) != 0);
} else DoRecalcSell = false;
if (DoRecalcBuy || DoRecalcSell) // что-то пошло не так при корректировке тейка
Print("!!! WARNING: DoRecalcBuy || DoRecalcSell [", DoRecalcBuy, " | ", DoRecalcSell, "] !!!");
// индикатор SAR изменяется только на новых барах
if (BarsOnly && new_bar(last_global_tf, GlobalTF) == false) return (0);
int count_buy = order_count(OP_BUY);
int count_sell = order_count(OP_SELL);
// динамический лот рассчитывается исходя из текущего размера собственных средств
// эмпирика: каждые 100$ свободных средств = 0.1 лота при EquityRisk = 0.1
// без динамики hi/lo по барам и учёта максимального количества ордеров
// внешняя переменная DynamicLot определяет источник (в порядке убывания агрессивности):
// 1) свободные для открытия ордера, 2) средства без учёта маржи, 3) баланс (практики не имеет)
double lot, lot_sell, lot_buy;
switch(DynamicLot)
{
case 1: lot = AccountFreeMargin() / 100 * RiskFactor; break;
case 2: lot = AccountEquity() / 100 * RiskFactor; break;
case 3: lot = AccountBalance() / 100 * RiskFactor; break;
default: lot = BaseLot; break;
}
if (EquLot)
{
lot_buy = NormalizeDouble(lot * MathPow(LotExp, MathMax(count_buy, count_sell)), LotDec);
lot_sell = lot_buy = MathMin(MathMax(lot_buy, BaseLot), MaxiLot);
}
else
{
lot_buy = NormalizeDouble(lot * MathPow(LotExp, count_buy), LotDec);
lot_buy = MathMin(MathMax(lot_buy, BaseLot), MaxiLot);
lot_sell = NormalizeDouble(lot * MathPow(LotExp, count_sell), LotDec);
lot_sell = MathMin(MathMax(lot_buy, BaseLot), MaxiLot);
}
/* вычисляем динамический шаг ордера, честно спизжено из робота Ilan1.6Dynamic
идея: попробовать разный шаг для buy/sell от близости Bid/Ask к hi и lo */
if (DynamicPips)
{
double pips = ( High[iHighest(NULL, DynPipTF, MODE_HIGH, DynPipBars, 1)]
- Low[iLowest(NULL, DynPipTF, MODE_LOW, DynPipBars, 1)] )
/ Point / DynPipCo;
// компактно \ (PipStep/DynPipCo) <= pips <= (PipStep*DynPipCo)
// реализует > if (pips < PipStep / DynPipCo) pips = PipStep / DynPipCo;
// алгоритм / if (pips > PipStep * DynPipCo) pips = PipStep * DynPipCo;
pips = NormalizeDouble(MathMin(MathMax(pips, PipStep / DynPipCo), PipStep * DynPipCo), 0);
} else pips = PipStep;
double dist_buy = Point * pips * MathPow( (count_buy > 1) ? PipExp : 1, count_buy );
double dist_sell = Point * pips * MathPow( (count_sell > 1) ? PipExp : 1, count_sell );
double sar0 = iSAR(Symbol(), GlobalTF, OrderAccel, OrderAccel * 10.0, 0);
double sar = iSAR(Symbol(), GlobalTF, OrderAccel, OrderAccel * 10.0, OrderShift);
if ( (sar > sar0 || (sar == sar0 && OrderShift == 0)) && sar0 > Ask /* + dist_buy / 3.0 */) // медвежий тренд
if (get_any_order(OP_BUYSTOP) >= 0) order_mod(sar, 0, sar + realtp);
else if (count_buy == 0 || (count_buy < MaxTickets && (sar + dist_buy) < price_edge(OP_BUY)))
order_open(OP_BUYSTOP, lot_buy, sar, 0, sar + realtp);
if ( (sar < sar0 || (sar == sar0 && OrderShift == 0)) && sar0 < Bid /* - dist_sell / 3.0 */) // бычий тренд
if (get_any_order(OP_SELLSTOP) >= 0) order_mod(sar, 0, sar - realtp);
else if (count_sell == 0 || (count_sell < MaxTickets && (sar - dist_sell) > price_edge(OP_SELL)))
order_open(OP_SELLSTOP, lot_sell, sar, 0, sar - realtp);
return(0);
}
/**************************************************************************************************
ТРЕЙЛИНГ СТОПОВ И ДОЛИВКА ПО ТРЕНДУ
**************************************************************************************************
Доливка по тренду лотом заданного процента от объема уже открытых позиций, при которой обеспечена
заданная StopProfit минимальная прибыль в случае хода цены против ставки и срабатывания stop-loss.
**************************************************************************************************/
void traileraiser()
{
static double old_sar = 0;
int i;
// SAR для трейл-стопа и доливки по тренду
double sar0 = iSAR(Symbol(), TrailTF, TrailAccel, TrailAccel * 10.0, 0);
double sar = iSAR(Symbol(), TrailTF, TrailAccel, TrailAccel * 10.0, TrailShift);
// текущие объемы открытых позиций
double buy_vol = get_volume(OP_BUY);
bool bullish = (sar <= sar0 && sar0 < Bid);
if (bullish && buy_vol > 0) // тренд "бычий", есть открытые позиции BUY
{
// текущее усреднение и цель
double buy_avg = price_median(OP_BUY);
double buy_tgt = buy_avg + (StopProfit + Spread) * Point;
// если значение SAR изменилось, а также
// цель < SAR и SAR + трейлинг < Bid, двигаем стопы всех BUY ордеров по SAR
if (sar != old_sar && sar > buy_tgt && sar < Bid - Trailing * Point)
{
for (i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i, OP_BUY) == true)
order_mod(0 /* price*/, (TrailShift > 0) ? sar : sar0 /* SL, TP, arrow */);
old_sar = sar;
}
// Доливка по тренду ( price_edge() может вернуть '0' при ошибке )
if (RaisePct > 0 && (RaiseAll || price_edge(OP_BUY, true) - Bid < 0))
{
// размер лота для "доливки" вычисляется как процент от текущих объемов открытых позиций,
// ограничен снизу и сверху значениями BaseLot и MaxiLot
double buy_raise = NormalizeDouble(MathMin(MathMax(buy_vol * RaisePct / 100, BaseLot), MaxiLot), LotDec);
/* расчитываем потенциальный уровень стопа после доливки:
new_buy_vol = buy_vol + buy_raise;
new_buy_avg = (buy_avg * buy_vol + Ask * buy_raise) / new_buy_vol;
new_buy_tgt = new_buy_avg + (StopProfit + Spread) * Point;
если new_buy_tgt укладывается в прибыль по StopProfit и находится выше SAR,
открываем ордер на продажу с рынка и ставим стоп по SAR
*/
if (sar < Bid - Trailing * Point && /* вычисление new_buy_tgt одной строкой */
sar > ((buy_avg * buy_vol + Ask * buy_raise) / (buy_vol + buy_raise) + (StopProfit + Spread) * Point) &&
price_edge(OP_BUY, true) < Bid - PipStep * Point && /* Ask - (PipStep + Spread) * Point */
order_open(OP_BUY, buy_raise, Ask) >= 0) order_mod(0 /* price*/, sar /* SL, TP, arrow */);
}
}
/////////////////////////////////////////// аналогично для SELL ///////////////////////////////////////////
// текущие объемы открытых позиций
double sell_vol = get_volume(OP_SELL);
bool bearish = (sar >= sar0 && sar0 > Ask);
if (bearish && sell_vol > 0) // тренд "медвежий", есть открытые позиции SELL
{
// текущее усреднение и цель
double sell_avg = price_median(OP_SELL);
double sell_tgt = sell_avg - (StopProfit + Spread) * Point;
// если значение SAR изменилось, а также
// цель > SAR и SAR - трейлинг > Ask, двигаем стопы всех SELL ордеров по SAR
if (sar != old_sar && sar < sell_tgt && sar > Ask + Trailing * Point)
{
for (i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i, OP_SELL) == true)
order_mod(0 /* price*/, (TrailShift > 0) ? sar : sar0 /* SL, TP, arrow */);
old_sar = sar;
}
// Доливка по тренду
if (RaisePct > 0 && (RaiseAll || price_edge(OP_SELL, true) > Ask))
{
// размер лота для "доливки" вычисляется как процент от текущих объемов открытых позиций,
// ограничен снизу и сверху значениями BaseLot и MaxiLot
double sell_raise = NormalizeDouble(MathMin(MathMax(sell_vol * RaisePct / 100, BaseLot), MaxiLot), LotDec);
/* расчитываем потенциальный уровень стопа после доливки:
new_sell_vol = sell_vol + sell_raise;
new_sell_avg = (sell_avg * sell_vol + Ask * sell_raise) / new_sell_vol;
new_sell_tgt = new_sell_avg - (StopProfit + Spread) * Point;
если new_sell_tgt укладывается в прибыль по StopProfit и находится выше SAR,
открываем ордер на продажу с рынка и ставим стоп по SAR
*/
if (sar > Ask + Trailing * Point && /* вычисление new_sell_tgt одной строкой */
sar < ((sell_avg * sell_vol + Bid * sell_raise) / (sell_vol + sell_raise) - (StopProfit + Spread) * Point) &&
price_edge(OP_SELL, true) > Ask + PipStep * Point && /* Bid + (PipStep + Spread) * Point */
order_open(OP_SELL, sell_raise, Bid) >= 0) order_mod(0 /* price*/, sar /* SL, TP, arrow */);
}
}
/* return (void); */
}
/******************************************************************************
Возвращает глобальный ID первого попавшегося ордера по его типу,
или (-1) если таких ордеров нет
******************************************************************************/
int get_any_order(int type)
{
for (int i = OrdersTotal() - 1; i >= 0; i--)
if ( is_mine_by_index(i) && (OrderType() == type) )
return (OrderTicket());
return (-1);
}
/******************************************************************************
Возвращает флаг включения выбранного ордера в обработку (свой/чужой)
Использует глобальные переменные:
AllOrders AutoStop
true true -- все ордера
true false -- все с явно заданным стопом
false * -- только свои (magic)
NB: Ордер должен быть предварительно выбран через 'OrderSelect'
******************************************************************************/
bool _is_mine()
{
return (OrderSymbol() == Symbol() &&
(OrderMagicNumber() == Magic || AllOrders) &&
(OrderMagicNumber() == Magic || OrderStopLoss() > 0 || AutoStop));
}
//-----------------------------------------------------------------------------
bool is_mine_by_ticket(int ticket)
{
return (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES) && _is_mine());
}
//-----------------------------------------------------------------------------
bool is_mine_by_index(int i)
{
return (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && _is_mine());
}
//-----------------------------------------------------------------------------
bool is_mine_by_index(int i, int type)
{
return (is_mine_by_index(i) && OrderType() == type);
}
/******************************************************************************
Возвращает признак новой свечи [в заданном таймфрейме]
******************************************************************************/
bool new_bar(datetime &last, int tf = 0 /* '0' - текущий ТФ */)
{
datetime current = iTime(Symbol(), tf, 0);
bool result = (last != current);
last = current;
return (result);
}
/******************************************************************************
Возвращает суммарный объем в лотах открытых позиций указанного типа.
******************************************************************************/
double get_volume(int type, bool all = true /* false = только прибыльных*/)
{
double vol = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i) && OrderType() == type && (all || OrderProfit() > 0))
vol += OrderLots();
return (vol);
}
/******************************************************************************
Возвращает количество открытых позиций заданного типа (-1 == все типы)
******************************************************************************/
int order_count(int type)
{
int result = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i) && (type == -1 || OrderType() == type))
result++;
return (result);
}
/******************************************************************************
Возвращает усреднение открытых ордеров по заданному типу
******************************************************************************/
double price_median(int type)
{
double vol = 0, lot = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
if (is_mine_by_index(i) && OrderType() == type)
{
lot += OrderLots();
vol += OrderOpenPrice() * OrderLots();
}
return ( (lot == 0) ? 0 : NormalizeDouble(vol / lot, Digits) );
}
/******************************************************************************
Возвращает пограничную цену открытого ордера по заданному типу
для OP_SELL: верхний ордер
для OP_BUY: нижний ордер
******************************************************************************/
double price_edge(int type, bool inner = true)
{
int ticket = order_edge(type, inner, false);
if (ticket >= 0 && OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
return (OrderOpenPrice());
return (0);
}
/******************************************************************************
Возвращает номер тикета нижнего/верхнего пограничного ордера
-------------------------------------------------------------------------------
type - тип ордеров (buy/sell)
inner - внутренний/внешний ордер в позиции "замка":
MIN, sell_2, sell_1, Bid, Ask, buy_1, buy_2, MAX
* для SELL внутренний - с наибольшей ценой - "sell_1"
* для BUY внутренний - с наименьшей ценой - "buy_1"
maxvol - наибольший/наименьший объем при одинаковой цене
******************************************************************************/
int order_edge(int type, bool inner = false, bool maxvol = false)
{
int ticket = -1;
double price = 0, vol;
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (is_mine_by_index(i) && OrderType() == type)
{
int ot = OrderTicket();
double ov = OrderLots();
double op = OrderOpenPrice();
if (price == 0) { ticket = ot; vol = ov; price = op; continue; } // первый в цикле
if (price == op)
{
if (ov > vol && maxvol == true) { ticket = ot; vol = ov; /* continue; */}
if (ov < vol && maxvol == false) { ticket = ot; vol = ov; /* continue; */}
continue;
}
switch (type)
{
case OP_BUY:
if (op < price && inner == true) { ticket = ot; vol = ov; price = op; /* break; */}
if (op > price && inner == false) { ticket = ot; vol = ov; price = op; /* break; */}
break;
case OP_SELL:
if (op > price && inner == true) { ticket = ot; vol = ov; price = op; /* break; */}
if (op < price && inner == false) { ticket = ot; vol = ov; price = op; /* break; */}
break;
}
}
}
return (ticket);
}
/******************************************************************************
Изменение SL/TP/цены ордера.
Значение тейка или стопа означает:
отрицательное - сброс;
нулевое - оставить без изменений;
NB: должен быть предварительно выбран через 'OrderSelect'
******************************************************************************/
int order_mod(double pr, double sl = 0, double tp = 0, bool arrow = false)
{
static color clr[] = { clrLightSkyBlue, clrLightPink };
int ort = OrderType();
double osl = NormalizeDouble(OrderStopLoss(), Digits);
double otp = NormalizeDouble(OrderTakeProfit(), Digits);
double opr = NormalizeDouble(OrderOpenPrice(), Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
pr = NormalizeDouble(pr, Digits);
if (ort == OP_BUY || ort == OP_SELL || pr == 0) pr = opr;
if (sl == 0) sl = osl; // оставляем без изменений
if (tp == 0) tp = otp; //
if (sl < 0) sl = 0; // сбрасываем в "0"
if (tp < 0) tp = 0; //
if (opr == pr && osl == sl && otp == tp) return (0); /* no op */
double level = MarketInfo(Symbol(), MODE_STOPLEVEL);
double lo_mark = Ask + level * Point; // граница сверху (нижняя)
double hi_mark = Bid - level * Point; // граница снизу (верхняя)
// переделано из 'case(op) {...}' - так более кратко
if ( (ort == OP_BUY && (sl > hi_mark || (tp > 0 && tp < lo_mark))) ||
(ort == OP_SELL && (tp > hi_mark || (sl > 0 && sl < lo_mark))) ||
(ort == OP_BUYLIMIT && pr > hi_mark) ||
(ort == OP_SELLLIMIT && pr < lo_mark) ||
(ort == OP_BUYSTOP && pr < lo_mark) ||
(ort == OP_SELLSTOP && pr > hi_mark) )
return (-1);
int ot = OrderTicket();
if(OrderModify(ot, pr, sl, tp, /* уже нормализованы */
OrderExpiration(), arrow ? clr[ort % 2] : CLR_NONE)) return (0);
Print("Order #", ot, " price: ", DTS(opr), " -> ", DTS(pr),
" sl: ", DTS(osl), " -> ", DTS(sl), " tp: ", DTS(otp), " -> ", DTS(tp),
" modify error: \'", GetLastError(), "\'");
return (-1);
}
/******************************************************************************
Открытие ордера
использует глобальную переменную Slippage
Возвращает глобальный номер ордера или (-1) в случае ошибки.
******************************************************************************/
int order_open(int op, double lot, double price, double sl = 0, double tp = 0, bool arrow = false)
{
int ticket;
static color clr[] = { clrBlue, clrRed };
static string sop[] = { "BUY", "SELL", "BUYLIMIT", "SELLIMIT", "BUYSTOP", "SELLSTOP" };
ticket = OrderSend(Symbol(), op,
NormalizeDouble(lot, Digits),
NormalizeDouble(price, Digits),
Slippage,
NormalizeDouble(sl, Digits),
NormalizeDouble(tp, Digits),
"", Magic, 0, bif(arrow, clr[op % 2], CLR_NONE));
if(ticket > 0 && OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
Print("new order placed : (", sop[op], ") by ", OrderOpenPrice());
else Print(sop[op], " error : ", GetLastError());
return ticket;
}
//---------------------------------------------------------------------------//
string DTS(double n, int d = -1)
{
if (d < 0) d = Digits;
return (DoubleToStr(n, d));
}
//---------------------------------------------------------------------------//
double bif(bool condition, double value_if_true, double value_if_false)
{
if (condition) return (value_if_true);
/* else */
return (value_if_false);
}
//+------------------------------------------------------------------+
bool draw_level(string name, int style, color col, double price, string tooltip = "\n")
{
bool result = true;
long chart_id = ObjectFind(name);
if (price == 0 && chart_id >= 0) // если price = 0, удалить
return (ObjectDelete(name));
if (chart_id < 0) // если не существует, создать
result = (ObjectCreate(name, OBJ_HLINE, 0, 0, price) && (chart_id = ObjectFind(name)) >= 0);
if (chart_id >= 0) // задать положение и tooltip (также и статические параметры, бо глюк в мт4)
result &= ( ObjectSet(name, OBJPROP_STYLE, style) &&
ObjectSet(name, OBJPROP_COLOR, col) &&
ObjectSet(name, OBJPROP_PRICE1, price) &&
ObjectSetString(chart_id, name, OBJPROP_TOOLTIP, tooltip)
);
return (result);
}
//+------------------------------------------------------------------+
bool draw_median(double buy, double buy_vol, double sell, double sell_vol, int profit = 0)
{
static string MPB = "median buy";
static string MPS = "median sell";
static string MPBP = "median buy profit";
static string MPSP = "median sell profit";
bool result = true;
if (buy > 0)
{
result &= draw_level(MPB, STYLE_DOT, cMPB, buy, "volume: " + DTS(buy_vol, LotDec));
if (profit > 0)
result &= draw_level(MPBP, STYLE_DASHDOTDOT, cMPB, buy + profit * Point, "profit: " + DTS(buy_vol * profit * MathPow(10, Digits) * Point, LotDec));
}
else result &= (draw_level(MPB, 0, 0, 0) && draw_level(MPBP, 0, 0, 0));
if (sell > 0)
{
result &= draw_level(MPS, STYLE_DOT, cMPS, sell, "volume: " + DTS(sell_vol, LotDec));
if (profit > 0)
result &= draw_level(MPSP, STYLE_DASHDOTDOT, cMPS, sell - profit * Point, "profit: " + DTS(sell_vol * profit * MathPow(10, Digits) * Point, LotDec));
}
else result &= (draw_level(MPS, 0, 0, 0) && draw_level(MPSP, 0, 0, 0));
return (result);
}
//---------------------------------------------------------------------------//
// закрываем перекрытые ордера
//---------------------------------------------------------------------------//
int close_overlapped(int minpips)
{
while (IsStopped() == false)
{
int tib = order_edge(OP_BUY, ClOverInner, false);
int tis = order_edge(OP_SELL, ClOverInner, false);
// берём пару самых дальних перекрёстных ордеров
if ( tib < 0 || tis < 0) break;
if (OrderSelect(tib, SELECT_BY_TICKET, MODE_TRADES) == false) break;
double tib_price = OrderOpenPrice();
double tib_lots = OrderLots();
if (OrderSelect(tis, SELECT_BY_TICKET, MODE_TRADES) == false) break;
double tis_price = OrderOpenPrice();
double tis_lots = OrderLots();
// вычисляем прибыль перекрытия в пунктах
int delta_pips = (tis_price - tib_price) / Point;
// если прибыль меньше заданной, прекращаем работу
if (delta_pips < minpips) break;
// закрываем больший ордер меньшим или равным
if (tib_lots > tis_lots) {
Print("close(B) #", tib, "(", DTS(tib_price), ") by #", tis, "(", DTS(tis_price), ")");
if (OrderCloseBy(tib, tis, cMPB) == false) break;
}
else {
Print("close(S) #", tis, "(", DTS(tis_price), ") by #", tib, "(", DTS(tib_price), ")");
if (OrderCloseBy(tis, tib, cMPS) == false) break;
}
}
return (0);
}
/* End of file */
Комментарии (4)
13 kipjatok001 Сообщений: 431 - Kipjatok001 Best Trader
Читайте комментарии
0 guest111 Автор Сообщений: 180
Зарегистрируйтесь или авторизуйтесь, чтобы оставить комментарий