Советники: Arbitrage Synthetic - страница 3

 
bas:

Maxim Dmitrievsky, если не секрет, какой у этого бота был пинг до сервера? и какое в среднем время исполнения? у меня 10мс и 200мс, и этого часто не хватает, чтобы успеть исполниться, пока арбитраж существует.

И как вы определяете, какая из двух оставшихся пар, кроме ведущей, будет ее "догонять"? Я например просто использую статистику по истории, обычно если ведущая EURUSD, то ее догоняет не кросс, а вторая usd-нога, но это не во всех тройках так.


к сожалению, эта тема уже мертвая.. пинги были нулевые. 200 мс уже много для лэтэнси арбитража (считайте 400, потому что сделку еще и закрыть надо + проскальзывания\маркапы)

просто в тестере смотрел и перебирал логики, ничего особенного не делал в этой стратегии.. основная идея была в том что если синтетик уже изменился а валютная пара нет, то скорее всего есть затуп в котировании и она скоро с ним сравняется. да и бессмысленно было бы на нее много времени тратить. Торговал этим ботом недолго, ставил на пару реалов - на одном чуть заработал на другом чуть просел, сделал выоды.

Выложил бота в основном для того, что много вопросов возникло по этой стратегии в последние пол года у людей. Что бы поделиться своим мнением. Многие об этом пишут или думают, а бесплатных примеров не было что бы пощупать. Дальнейшая оптимизация бессмысленна, т.к. современные брокеры не предназначены для hft, да и вообще 3-point арбитраж это миф, не существует такого арбитража ни в одноногом ни в 3-ногом виде.

 

Ну, я бы не сказал, что совсем уж мертвая) в некоторых валютах (TRY, NZD) перекосы, бывает, длятся часами) правда, заранее этого не узнаешь, да и сидеть столько в сделке неинтересно.

Синтетик же состоит из двух пар. Обычно "догоняет" только одна из них, а третья вообще стоит на месте. Я потому и спрашивал, как определять, какая из двух будет догоняющей.

А закрытие ж делается после схлопывания арбитража, там время исполнения уже не так существенно.

Почему "не существует"? я вот его наблюдаю регулярно) правда, скорости не хватает.

 
bas:

Ну, я бы не сказал, что совсем уж мертвая) в некоторых валютах (TRY, NZD) перекосы, бывает, длятся часами) правда, заранее этого не узнаешь, да и сидеть столько в сделке неинтересно.

Синтетик же состоит из двух пар. Обычно "догоняет" только одна из них, а третья вообще стоит на месте. Я потому и спрашивал, как определять, какая из двух будет догоняющей.

А закрытие ж делается после схлопывания арбитража, там время исполнения уже не так существенно.

Почему "не существует"? я вот его наблюдаю регулярно) правда, скорости не хватает.


из-за скорости не существует

и возникает зачастую из-за задержек в котировании, вам приходит индикативная котировка которая либо запаздывает либо вообще не реальная

те перекосы о которых вы говорите фиксятся потом дц, когда они это замечают.. 

Я потому и спрашивал, как определять, какая из двух будет догоняющей.

по сути никак, только экспериментально или торговать в 3 ноги. Или, по крайней мере с 33% вероятностью отстает именно наша пара, что уже не мало :)

 
Ну ладно, не существует так не существует)
 
bas:
Ну ладно, не существует так не существует)

нет ну Вы все равно попытайтесь, если угодно, я же не истина в последней инстанции :)

сам все на своем опыте проверяю.. и на опыте других тоже. А если времени жалко то лучше не стоит.

Как в Ералаше - "Здесь рыбы нет!" (несколкьо раз)

- А кто это говорит то??

- кто кто, директор стадиона!

 
Maxim Dmitrievsky:

нет ну Вы все равно попытайтесь, если угодно, я же не истина в последней инстанции :)

сам все на своем опыте проверяю.. и на опыте других тоже. А если времени жалко то лучше не стоит.

Как в Ералаше - "Здесь рыбы нет!" (несколкьо раз)

- А кто это говорит то??

- кто кто, директор стадиона!


- директор катка.

 

Если выкладывать пример треугольника, то можно сделать эстетичней, а именно, заменить OnTimer, пропускающий тики, на OnChartEvent, который будет принимать тики со всех инструментов, индикатор отсюда - https://www.mql5.com/en/articles/234

Вцелом, да, рыбы нет, пипсовка не для ритейла, если учесть спред + комиссию, то на главном треугольнике будет от силы сделки 3 в год с мизерным профитом, и тот брокер может не отдать потому что в идеальном мире EURUSD / GBPUSD = EURGBP, а если произошло обратное, то это - нерыночная котировка :)

#include <AIV/Trades.mqh>
#include <AIV/Charts.mqh>

input int InpMagic = 0;
input double InpFactor = 2;
input double InpVolume = 0.01;
input double InpCommission = 30;
input string iACName = "EURUSD";
input string iBCName = "GBPUSD";
input string iABName = "EURGBP";

int iDirection;

SSymbol iACData = {0};
SSymbol iBCData = {0};
SSymbol iABData = {0};

SSeries iSeries[];

CSets * iSets;
CHelpers * iHelpers;
CPositions * iPositions;

void OnDeinit(const int reason)
{
    delete(iSets);
    delete(iHelpers);
    delete(iPositions);
}

int OnInit()
{
    long chart = ChartID();

    iSets = new CSets();
    iHelpers = new CHelpers();
    iPositions = new CPositions();

    iCustom(iACName, PERIOD_M1, "AIV\\Spy", chart, 1);
    iCustom(iBCName, PERIOD_M1, "AIV\\Spy", chart, 2);
    iCustom(iABName, PERIOD_M1, "AIV\\Spy", chart, 3);

    return 0;
}

void Trade()
{
    int positions = PositionsTotal();

    double incomeAC = iPositions.getPositionsIncome(iACName, 0, InpMagic);
    double incomeBC = iPositions.getPositionsIncome(iBCName, 0, InpMagic);
    double incomeAB = iPositions.getPositionsIncome(iABName, 0, InpMagic);

    // Align volatility of instruments

    double sizeAC = InpVolume / iHelpers.getTickCost(iACName);
    double sizeBC = InpVolume / iHelpers.getTickCost(iBCName);
    double sizeAB = InpVolume / iHelpers.getTickCost(iABName);

    // If we've got profit in triangle, close positions

    if (positions > 0)
    {
        if (incomeAC + incomeBC + incomeAB > 0) 
        {
            iPositions.closePositions(NULL, 0, InpMagic);
            return;
        }
    }
    else
    {
        int direction = isGap();

        // When synthetic is above EURGBP

        if (direction == 1) 
        {
            iDirection = direction;
            iPositions.openSimplePosition(iACName, iDirection * -1, sizeAC, 0, 0, 0, InpMagic);
            iPositions.openSimplePosition(iBCName, iDirection, sizeBC, 0, 0, 0, InpMagic);
            iPositions.openSimplePosition(iABName, iDirection, sizeAB, 0, 0, 0, InpMagic);
        }
        else if (direction == -1) // When EURGBP is higher
        {
            iDirection = direction;
            iPositions.openSimplePosition(iACName, iDirection, sizeAC, 0, 0, 0, InpMagic);
            iPositions.openSimplePosition(iBCName, iDirection * -1, sizeBC, 0, 0, 0, InpMagic);
            iPositions.openSimplePosition(iABName, iDirection * -1, sizeAB, 0, 0, 0, InpMagic);
        }
    }
}

int isGap()
{
    if (iACData.mUnit <= 0 || iBCData.mUnit <= 0 || iABData.mUnit <= 0)
    {
        return 0;
    }

    double X = iACData.mUnit / iBCData.mUnit;
    double Y = iABData.mUnit;
    double spread = 2 * (iACData.mMean + iBCData.mMean + iABData.mMean);

    double commission = 
        2 * iACData.mUnit * iHelpers.moneyToPips(iACName, InpVolume, InpCommission * InpVolume) + 
        2 * iBCData.mUnit * iHelpers.moneyToPips(iBCName, InpVolume, InpCommission * InpVolume) + 
        2 * iABData.mUnit * iHelpers.moneyToPips(iABName, InpVolume, InpCommission * InpVolume);

    // When distance EURUSD / GBPUSD - EURGBP > Commision + Spread

    if (X - Y - spread - commission > 0)
    {
        return 1;
    }
    else if (Y - X - spread - commission > 0) // Vice versa
    {
        return -1;
    }

    return 0;
}

void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
    if (id > CHARTEVENT_CUSTOM) 
    {
        string message[];

        // Aggregate prices from 3 charts here, every "sparam" contains data in format "EURUSD:1.22350:30" or "GBPUSD:1.52450:15" or "EURGBP:1.22350:3"

        StringSplit(sparam, ':', message);

        if (ArraySize(message) < 3)
        {
            return;
        }

        string symbol = message[0];
        int event = id - CHARTEVENT_CUSTOM;
        double close = StringToDouble(message[1]);
        double spread = StringToDouble(message[2]) * SymbolInfoDouble(symbol, SYMBOL_POINT);

        if (symbol == iACName)
        {
            iACData.mName = symbol;
            iACData.mUnit = close;
            iACData.mMean = spread;
        }
        else if (symbol == iBCName)
        {
            iBCData.mName = symbol;
            iBCData.mUnit = close;
            iBCData.mMean = spread;
        }
        else if (symbol == iABName)
        {
            iABData.mName = symbol;
            iABData.mUnit = close;
            iABData.mMean = spread;
        }
 
        // Trade only when we've got prices from all 3 pairs

        if (iACData.mUnit > 0 && iBCData.mUnit > 0 && iABData.mUnit > 0)
        {
            Trade();
        }
    }
}

На всякий случай и упрощеный код индикатора Spy :)

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1

input long InpChart = 0;
input ushort InpEventId = 0;

int OnCalculate (
    const int bars,
    const int counted,
    const datetime& times[],
    const double& opens[],
    const double& highs[],
    const double& lows[],
    const double& closes[],
    const long& ticks[],
    const long& volumes[],
    const int& spreads[])
{
    string close = DoubleToString(closes[bars - 1]);
    string spread = DoubleToString(spreads[bars - 1]);
    EventChartCustom(InpChart, InpEventId, (long) Period(), bars, Symbol() + ":" + close + ":" + spread); // Translate ticks from all charts to a single event handler
    return bars;
}
 
Andy Sanders:

На всякий случай и упрощеный код индикатора Spy :) 

Альтернативый вариант.

Особенности языка mql5, тонкости и приёмы работы
Особенности языка mql5, тонкости и приёмы работы
  • 2018.01.28
  • www.mql5.com
В данной теме будут обсуждаться недокументированные приёмы работы с языком mql5, примеры решения тех, или иных задач...
 

Можно и так, но в моем случае через sparam передается пачка данных "EURUSD:1.22350:30", чтобы не захламлять код советника отдельными вызовами SymbolInfoTick по каждому символу

 

И если кого интересует, есть интересная имплементация Парного Трейдинга с ребалансировкой и удержанием, то есть не для счетов со свопом, только на реальных акциях
https://www.quantconnect.com/forum/discussion/1257/pairs-trading-with-coke--pepsi


Причина обращения: