Especialistas: Arbitrage Synthetic - página 3

 
bas:

Maxim Dmitrievsky, se não for segredo, qual foi o ping para o servidor desse bot? E qual é o tempo médio de execução? Tenho 10ms e 200ms, e isso geralmente não é suficiente para ser executado enquanto a arbitragem existe.

E como você determina qual dos dois pares restantes, além do principal, irá "recuperar o atraso"? Eu, por exemplo, apenas uso estatísticas históricas, geralmente se o EURUSD estiver liderando, não é o cruzamento que o alcança, mas a segunda perna do USD, mas esse não é o caso em todos os triplos.


infelizmente, esse tópico já está morto. os pings eram zero. 200 ms já é muito para arbitragem de latência (considere 400 ms, porque o negócio ainda precisa ser fechado + slippages/markups).

A ideia principal era que, se o sintético já tivesse mudado e o par de moedas não, então provavelmente haveria uma queda na cotação e ela logo se igualaria a ele, e seria inútil gastar muito tempo com isso. Negociei com esse bot por um curto período, coloquei alguns reais - em um deles ganhei um pouco, no outro perdi um pouco, fiz deduções.

Coloquei o bot principalmente pelo fato de terem surgido muitas perguntas sobre essa estratégia no último semestre. Para compartilhar minha opinião. Muitas pessoas escrevem ou pensam sobre isso, mas não havia exemplos gratuitos para sentir. A otimização adicional é inútil, pois as corretoras modernas não são projetadas para hft e, em geral, a arbitragem de 3 pontos é um mito, pois não existe tal arbitragem na forma de uma perna ou de 3 pernas.

 

Em algumas moedas (TRY, NZD), as distorções podem durar horas, mas não é possível saber com antecedência e não é interessante ficar em uma negociação por tanto tempo.

O Synthetic consiste em dois pares. Normalmente, apenas um deles "se recupera", e o terceiro fica parado. É por isso que perguntei como determinar qual dos dois pares estará se recuperando.

E o fechamento é feito após o colapso da arbitragem, em que o tempo de execução não é tão importante.

Por que "não existe"? Eu o observo regularmente, mas não tenho velocidade suficiente.

 
bas:

Em algumas moedas (TRY, NZD), as distorções podem durar horas, mas não é possível saber com antecedência e não é interessante ficar em uma negociação por tanto tempo.

O Synthetic consiste em dois pares. Normalmente, apenas um deles "se recupera", e o terceiro fica parado. É por isso que perguntei como determinar qual dos dois pares estará se recuperando.

E o fechamento é feito após o colapso da arbitragem, em que o tempo de execução não é tão importante.

Por que "não existe"? Eu a vejo regularmente, mas não tenho velocidade suficiente.


Ela não existe por causa da velocidade.

e geralmente ocorre devido a atrasos na cotação, você recebe uma cotação indicativa que está atrasada ou não é real.

Essas distorções de que você está falando são corrigidas posteriormente pelas corretoras quando elas percebem...

É por isso que perguntei como determinar qual das duas vai se recuperar.

Basicamente, não é possível, apenas experimentalmente ou negociando em três pernas. Ou, pelo menos, com 33% de probabilidade de que seja o nosso par que esteja ficando para trás, o que não é um número pequeno :)

 
Ok, ele não existe, então não existe)
 
bas:
Tudo bem, ele não existe, então não existe)

Não, mas você ainda tenta, se quiser, eu não sou a verdade em última instância :))

Eu verifico tudo com base em minha própria experiência... e na experiência de outras pessoas também. E se o tempo for uma pena, é melhor não fazer isso.

Como em Yeralash - "Não há peixes aqui!" (várias vezes)

- Quem disse isso?

- Quem é quem, o diretor do estádio!

 
Maxim Dmitrievsky:

Não, bem, você ainda pode tentar se quiser, mas eu não sou a verdade em última instância :)

Eu verifico tudo com base em minha própria experiência... e na experiência de outras pessoas também. E se o tempo for uma pena, é melhor não fazer isso.

Como em Yeralash - "Não há peixes aqui!" (várias vezes)

- Quem disse isso?

- Quem é quem, o diretor do estádio!


- O diretor do rinque de patinação.

 

Se você postar um exemplo de triângulo, poderá torná-lo mais agradável esteticamente, ou seja, substituir OnTimer, que pula os ticks, por OnChartEvent, que receberá ticks de todos os instrumentos, o indicador daqui - https://www.mql5.com/en/articles/234

Em geral, sim, não há peixe, pipsing não é para o varejo, se você levar em conta o spread + comissão, no triângulo principal, haverá apenas 3 negociações por ano com um lucro escasso, e esse corretor pode não dar isso porque em um mundo ideal EURUSD / GBPUSD = EURGBP, e se o oposto aconteceu, é uma cotação não de mercado :)

#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);

    // Alinhar a volatilidade dos instrumentos

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

    // Se tivermos lucro no triângulo, fechamos as posições

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

        // Quando o sintético estiver acima do 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) // Quando o EURGBP está mais alto
        {
            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);

    // Quando a distância EURUSD / GBPUSD - EURGBP > Comissão + 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;
        }
 
        // Negocie somente quando tivermos preços de todos os 3 pares

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

Por precaução e código simplificado do indicador 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); // Traduzir ticks de todos os gráficos para um único manipulador de eventos
    return bars;
}
 
Andy Sanders:

Por precaução e código simplificado do indicador Spy :)

Variante alternativa.

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

Você pode fazer isso dessa forma, mas, no meu caso, passo vários dados "EURUSD:1.22350:30" pelo sparam, para não sobrecarregar o código do EA com chamadas SymbolInfoTick separadas para cada símbolo

 

E, se alguém estiver interessado, há uma implementação interessante do Pair Trading com rebalanceamento e manutenção, que não é para contas de swap, apenas em ações reais
https://www.quantconnect.com/forum/discussion/1257/pairs-trading-with-coke--pepsi.