EA: 组合套利 - 页 3

 
bas:

马克西姆-德米特里耶夫斯基,如果这不是秘密的话,这个机器人服务器的 ping 是多少? 平均执行时间是多少? 我有 10ms 和 200ms,这往往不足以在套利存在时执行。

除了领先的一对,你如何确定剩下的两对中哪一对会 "迎头赶上"?例如,我只是使用历史统计数据,通常情况下,如果欧元兑美元领先,追赶它的不是交叉盘,而是第二段美元走势,但并非所有三方走势都是如此。


不幸的是,这个话题已经死了。对于延迟套利来说,200 毫秒已经很多了(考虑 400 毫秒,因为交易仍需完成 + 滑点/标记)。

主要的想法是,如果合成已经发生变化,而货币对没有变化,那么很可能是报价下降,很快就会与之持平。我用这个机器人交易了很短的时间,投入了几个雷亚尔--其中一个赚了一点,另一个亏了一点,还做了扣除。

我使用该机器人的主要原因是,在过去的半年里,人们对这一策略提出了很多问题。分享一下我的看法。很多人都写过或想过这个问题,但没有免费的例子可以感受。进一步优化是没有意义的,因为现代经纪商不是为 hft 设计的,而且一般来说 3 点套利是一个神话,无论是单脚还是 3 脚形式都不存在这种套利。

 

在某些货币(新土耳其里拉、新西兰元)中,偏差可能会持续数小时),但您无法提前发现,而且在交易中坐等那么久也没什么意思。

合成汇率由两个货币对组成。通常只有一对 "跟上",而第三对则原地踏步。这就是为什么我问如何确定哪一对会跟上。

而平仓是在套利崩溃后进行的,执行时间 并不那么重要。

为什么 "不存在"? 我经常观察)但我没有足够的速度。

 
bas:

在某些货币(新土耳其里拉、新西兰元)中,偏差可能会持续数小时),但您无法提前发现,而且在交易中坐等这么长时间也没什么意思。

合成汇率由两个货币对组成。通常只有一对 "跟上",而第三对则原地踏步。这就是为什么我问如何确定哪一对会跟上。

而平仓是在套利崩溃后进行的,执行时间 并不那么重要。

为什么 "不存在"? 我经常看到)但我的速度不够快。


不存在是因为速度不够快。

这种情况经常出现是因为报价延迟,你得到的指示性报价要么是延迟的,要么根本不是真实的。

你说的那些失真,经纪公司发现后会及时修正......

这就是为什么我问如何确定这两种情况中哪一种会迎头赶上。

基本上,你不能,只能通过实验或三条腿交易。或者至少有 33% 的概率是我们的货币对落后,这可不是一个小数字:)

 
好吧,它不存在,所以它不存在)。
 
bas:
好吧,它不存在,所以它不存在。)

不,但如果你愿意,你还是可以试试,我不是最后的真理:)

我根据自己的经验......也根据他人的经验来检验一切。如果时间紧迫,最好不要这样做。

就像《耶拉拉什》里说的--"这里没有鱼!"(好几次)

- 谁说的?

- 谁是谁,体育馆馆长!

 
Maxim Dmitrievsky:

好吧,如果你想的话,你还是可以试试看的,我不是最后的真理:)

我根据自己的经验......以及他人的经验来检验一切。如果时间紧迫,最好还是不要。

就像《耶拉拉什》里说的--"这里没有鱼!"(好几次)

- 谁说的?

- 谁是谁,体育馆馆长!


- 溜冰场场长

 

如果您发布一个三角形示例,您可以使其更美观,即用OnChartEvent 代替 OnTimer(跳过刻度线),OnChartEvent 将接收来自所有工具的刻度线,这里的指标 - https://www.mql5。com/en/articles/234

总的来说,是的,没有鱼,点差不适合散户,如果考虑到点差+佣金,在主三角上每年只有 3 次交易,利润微薄,而且经纪商可能不会给,因为在理想世界中欧元兑美元/英镑兑美元=欧元兑英镑,如果发生相反情况,则是非市场报价:)

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

    // 调整工具的波动性

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

    // 如果我们在三角形中获利,平仓

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

        // 当合成高于 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) // 当欧元兑英镑走高时
        {
            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);

    // 当距离 EURUSD / GBPUSD - EURGBP > 佣金 + 利差时

    if (X - Y - spread - commission > 0)
    {
        return 1;
    }
    else if (Y - X - spread - commission > 0) // 反之亦然。
    {
        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;
        }
 
        // 只有当我们得到所有 3 对货币对的价格时才进行交易

        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); // 将所有图表中的刻度转换为单个事件处理程序
    return bars;
}
 
Andy Sanders:

以防万一,简化 Spy 指标代码 :)

替代变量。

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

您可以这样做,但在我的案例中,我通过 sparam 传递了大量数据 "EURUSD:1.22350:30",这样就不会因为对每个符号单独调用 SymbolInfoTick 而使 EA 代码变得杂乱无章。

 

如果有人感兴趣,有一个有趣的配对交易实施方法,可以再平衡和持有,但不用于掉期账户,只用于真实股票
https://www.quantconnect.com/forum/discussion/1257/pairs-trading-with-coke--pepsi。