Rostislav Kudryashov
Rostislav Kudryashov личный блог
08 февраля 2020, 22:34

Беспроигрышная стратегия для фьючерсов. Чудеса и их разоблачение

О чудесах календарного спреда фьючерсов уже доложено в статье некого 3Qu. smart-lab.ru/blog/586202.php

Поэтому сразу приступим к разоблачению. Какая проделана работа.
В Qukk'е на QLua написан монитор, который с 2020.01.17 по 2020.02.06 каждые 200 мсек записывал в текстовый файл офера и биды RIH0 и RIM0. Эти данные представлены как стандартный файл котировок Метастока, где Open = Bid(H0), High = Ask(H0), Low = Bid(M0), Close = Ask(M0).
Программа WealthLab показывает график этого файла, не понимая его значения. Но мой скрипт на C# по этим данным строит другие графики:

Диаграмма из WealthLab
Две точечные линии, зелёные и красные ступеньки, в середине центральной панели:
1) SpreadLong = Ask(H0) — Bid(M0).
2) SpreadShrt = Bid(H0) — Ask(M0).
По цене SpreadShrt приходится продавать спред фьючерсов, когда он дорог а по цене SpreadLong — покупать спред, когда он подешевл.
Чтобы определить, дорог спред или дёшев, строим скользящие средние  с горизонтом 10 мин (серые линии)
3) SmaLong.
4) SmaShrt.
Для наглядности проводим сверху и снизу две синие линии, сдвинутые на 30 руб, сконвертированные в пункты фьючерса.
5) UprLong.
6) LwrLong.
Если SpreadLong выше UprLong (на зелёном фоне), считаем фьючерс дорогим и пригодным к продаже.
Если SpreadShrt ниже LwrShrt (на розовом фоне), это случай для покупки.
Коды программ прилагаются.

Так вот, если вкратце, то чудесам мешают три обстоятельства.
Во-первых, средний за день спред котировок RIM0 составляет от 70 до 130 пунктов, т.е. от 0.05% до 0.09%. И это уже перекрывает сколь-нибудь доступный выигрыш от колебаний спреда.
Во-вторых, если кто захочет купить-продать выгоднее, чем в биды-офера, рискует промахнуться и остаться с одним фьючерсом, стоящим против рынка.
И в-третьих. Если спред фьючерсов пойдёт против открытой позиции, ожидание исправления рынка может оказаться слишком долгим и безнадёжным.
Колебания спреда фьючерсов вокруг теоретического равновесного уровня значительны и продолжительны. За 3 отмониторенных недели спред сходил от значения 1636 к 1516 и затем обратно к 1651. Так что говорить о «беспроигрышности» стратегии можно с большой натяжкой.

Значительный выигрыш во многие проценты за день возможен, если совершать сделки посередине между бидами и оферами. Но это доступно только волшебникам. У остальных такая удача будет столь редка, что не оправдает всей затеи.
А если играть по бидам и оферам, то каждый день интрадея будет убыток в несколько десятых процента.
Если кто захочет проверить работу скрипта WealthLab'а, могу почтой послать отмониторенные биды-офера. Они представлены как 1-минутные, чтобы WealthLab мог их сгруппировать от 10- до 60-минуток.
Скрипт-монитор QLua испоьзует также мои библиотечные скрипты SetPaths64.lu, QuikUtil(qu).lua, QuikConst(qc).lua и LuaUtil(lu).lu. Достаточно дееспособный программист сможет заменить их своим кодом.
Вот скрипт C# для WealthLab:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms; // DialogResult
using WealthLab;
using WealthLab.Indicators;
//using mw  = MyWealth;
//using mwu = MyWealth.Utils;

namespace WealthLab.Strategies
{
public struct Arg {
public static double MinMoney = 30;   // Минимальный выигрыш в рублях
public static double ProfitFactor = 1;// Доля MinMoney для выхода из позиции
public static int PeriodMins = 10;    // Период SMA, минуты
public static TimeSpan TimeIni = new TimeSpan (10, 10, 0); // Начало игры
public static TimeSpan TimeBan = new TimeSpan (18, 00, 0); // Запрет входа
public static TimeSpan TimeFin = new TimeSpan (18, 40, 0); // Конец игры
}
public struct Data {
public static double SecPriceStep;// Шаг цены в пунктах фьючерса
public static double DealFee = 4; // Комиссия за сделку в рублях
public static double MinProfit;   // Минимальный выигрыш в пунктах
public static int PeriodBars;     // Период SMA, бары
}
   
public class CalendarSpreadTwo : WealthScript
{ 
  DataSeries SpreadLong, SpreadShrt, UprLong, LwrShrt;
  DataSeries SpreadMid, UprMid, LwrMid;
    
  protected override void Execute() {
    ClearDebug();
    if (! Bars.IsIntraday || ! Bars.Scale.Equals (BarScale.Minute)) {
      PrintDebug ("Bar.Scale Minute only!");
      return;
    }
    double stepPrice // Рублёвая цена для Data.SecPriceStep
     ,moneyMargin    // Среднее ГО контракта, руб
     ,moneyFct;      // Единица контракта, руб
    Prepare (out stepPrice, out moneyMargin, out moneyFct);
    //***
    Pos pos = new Pos();
    double win = 0; double ttlWin = 0;
    double minWin = Double.MaxValue; double maxWin = Double.MinValue;
    int bar = Data.PeriodBars; TimeSpan curTime = new TimeSpan (0);
    for ( ; ; ++bar) {
      curTime = new TimeSpan(Date[bar].Hour, Date[bar].Minute, 0);
      if (curTime < Arg.TimeIni)
        goto Next;
      //if (pos.Type == 1  && SpreadShrt[bar] >= UprShrt[bar] ||
      //    pos.Type == -1 && SpreadLong[bar] <= LwrLong[bar])
      if (ExitPos (
        bar, false, pos, ref win, ref minWin, ref maxWin, ref ttlWin))
        goto Next;
      if (curTime >= Arg.TimeBan || pos.Type != 0)
        goto Next;
      if (SpreadShrt[bar] < LwrShrt[bar]) {        // Покупаем
      //if (SpreadMid[bar] < LwrMid[bar]) {        // Покупаем
        EnterPos (1, bar, pos);
      } else if (SpreadLong[bar] > UprLong[bar]) { // Продаём
      //} else if (SpreadMid[bar] > UprMid[bar]) { // Продаём
        EnterPos (-1, bar, pos);
      }
      Next:          
        if (curTime >= Arg.TimeFin)
          break;
    } // for ( ; ; ++ bar
    ExitPos (bar, true, pos, ref win, ref minWin, ref maxWin, ref ttlWin);
    //***
    if (pos.PosNo > 0) {
      double margin = 2 * moneyMargin / moneyFct;
      double fee = Data.DealFee / moneyFct * pos.PosNo;
      double pct = (ttlWin - fee) / margin * 100;
      PrintDebug (String.Format("{0,-7};{1,-6};{2,-5};{3,-7};{4,-6};{5,-5}"
        ,"min", "max", "avr", "ttl", "fee", "pct"));
      PrintDebug (String.Format (
        "{0,7:F2};{1,6:F2};{2,5:F2};{3,7:F2};{4,6:F2};{5,5:F2}"
        ,minWin, maxWin, ttlWin / pos.PosNo,  ttlWin, fee, pct));
    }
  } // Execute()

  bool EnterPos (int type, int bar, Pos pos) {
    pos.Type = type;
    pos.EntryBar = bar;
    pos.EntryPrice = SpreadPrice (type, bar);
    pos.PosNo = pos.PosNo + 1;
    return true;
  } // EnterPos()

  double SpreadPrice (int buySell, int bar) {
    if (buySell == 1) {
      return SpreadLong[bar];
      //double ask1 = High[bar]; double bid2 = Low[bar];
      //return ask1 - bid2; // Для покупки спред дорог
    } else {
      return SpreadShrt[bar];
      //double bid1 = Open[bar]; double ask2 = Close[bar];
      //return bid1 - ask2; // Для продажи спред дёшев
    }
  }
    
  bool ExitPos (int bar, bool atOnce, Pos pos, ref double win
  ,ref double minWin, ref double maxWin, ref double ttlWin) {
    if (pos.Type == 0)
      return false;
    int newType = pos.Type == 1 ? -1 : 1;
    double exitPrice = SpreadPrice (newType, bar);
    bool mustExit = pos.Type == 1
      ? exitPrice >= pos.EntryPrice + Data.MinProfit * Arg.ProfitFactor
      : exitPrice + Data.MinProfit * Arg.ProfitFactor <= pos.EntryPrice;
    if (! mustExit && ! atOnce) return false;   
    pos.ExitBar = bar;
    pos.ExitPrice = exitPrice;
    win = 0;
    if (pos.Type == 1) // Продаём лонг
      win = pos.ExitPrice - pos.EntryPrice;
    else               // Откупаем шорт
      win = pos.EntryPrice - pos.ExitPrice;
    minWin = Math.Min (minWin, win);
    maxWin = Math.Max (maxWin, win);
    ttlWin += win;
    if (pos.PosNo == 1)     
      PrintDebug (
        String.Format ("{0,-4};{1,1}:{2,-6};{3,-6};{4,-7};{5,-7};{6,-7}"
        ,"nn","*", "nBar", "xBar", "nPrc", "xPrc", "win"));
    PrintDebug (String.Format (
      "{0,4};{1,1};{2,6};{3,6};{4,7:F2};{5,7:F2};{6,7:F2}"
      ,pos.PosNo, pos.Type == -1 ? "-" : "+", pos.EntryBar, pos.ExitBar
      ,pos.EntryPrice, pos.ExitPrice, win));
    pos.Type = 0;
     return true;
  } // ExitPos()
    
  void Prepare (out double stepPrice, out double moneyMargin
      ,out double moneyFct) {
    PrintDebug (StrategyName + " " + Bars.Symbol);
    Data.SecPriceStep = stepPrice = moneyMargin = moneyFct = 0;
    if (Bars.Symbol.Contains ("_OneOfBR")) {
      Data.SecPriceStep = 0.01;
      stepPrice   = 6.14629;
      moneyMargin    = 4700;
    } else if (Bars.Symbol.Contains ("_OneOfGD")) {
      Data.SecPriceStep = 0.1;
      stepPrice   = 6.29685;
      moneyMargin    = (7756.08+790879)/2;
    } else if (Bars.Symbol.Contains ("_OneOfRI")) {
      Data.SecPriceStep = 10;
      stepPrice   = 12.29258;
      moneyMargin    = 24000;
    } else if (Bars.Symbol.Contains ("_OneOfSi") ||
     Bars.Symbol.Contains ("_OneOfGZ")) {
      Data.SecPriceStep = 1;
      stepPrice   = 1;
      moneyMargin    = 4500;
      Data.DealFee = 3;
    } else if (Bars.Symbol.Contains ("_OneOfSR")) {
      Data.SecPriceStep = 1;
      stepPrice   = 1;
      moneyMargin    = 4500;
      Data.DealFee = 2.50;
    } else
      return;
    moneyFct = stepPrice / Data.SecPriceStep;
    Data.MinProfit = Arg.MinMoney / moneyFct;      
    SetPeriodBars();
    SpreadLong = High - Low;
    SpreadShrt = Open - Close;
    SpreadLong.Description = "SpeadLong";
    SpreadShrt.Description = "SpeadShrt";
    int m = Bars.Count-1;
    PrintDebug ("Spreads  " + SpreadLong[m] + " " + SpreadShrt[m]);
    PrintDebug ("HighLows " + High[m] + " " + Low[m]);
    DataSeries smaLong = SMA.Series (SpreadLong, Data.PeriodBars);
    smaLong.Description = "SmaLong";
    DataSeries smaShrt = SMA.Series (SpreadShrt, Data.PeriodBars);
    smaShrt.Description = "SmaShrt";
    UprLong = smaLong + Data.MinProfit;
    UprLong.Description = "UprLong";
    LwrShrt = smaShrt - Data.MinProfit;
    LwrShrt.Description = "LwrShrt";
    double avrLong = 0; double avrShrt = 0; double ofrbid = 0;
    for (int i = 0; i < Bars.Count; ++i) {
      avrLong += SpreadLong[i]; avrShrt += SpreadShrt[i];
      ofrbid += Close[i] - Low[i];
    }
    avrLong /= Bars.Count; avrShrt /= Bars.Count;
    ofrbid /= Bars.Count;
    int k = -23;
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2} ({2:F0} руб)"
      ,"Мин.выигрыш", Data.MinProfit, Arg.MinMoney));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Профит-фактор", Arg.ProfitFactor));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}, пункты"
      ,"Шаг цены фьючерса", Data.SecPriceStep));
    PrintDebug (String.Format ("{0,"+(k+3)+"}{1,7}"
      ,"Период в минутах", Arg.PeriodMins));
    PrintDebug (String.Format ("{0,"+(k+3)+"}{1,7}"
      ,"Период в барах", Data.PeriodBars));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Максимум лонг-спреда", SpreadLong.MaxValue));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Минимум лонг-спреда", SpreadLong.MinValue));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Максимум шорт-спреда", SpreadShrt.MaxValue));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Минимум шорт-спреда", SpreadShrt.MinValue));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Коридор лонг-спреда", SpreadLong.MaxValue - SpreadLong.MinValue));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Коридор шорт-спреда", SpreadShrt.MaxValue - SpreadShrt.MinValue));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Средний лонг-спред", avrLong));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Средний шорт-спред", avrShrt));
    PrintDebug (String.Format ("{0,"+k+"}{1,7:F2}"
      ,"Средний офер-бид", ofrbid));
    ChartPane cpSpread = CreatePane (50, true, true);
    DrawLabel (cpSpread, "Spread");
    PlotSeries (cpSpread, smaLong, Color.Black, LineStyle.Solid, 1);
    PlotSeries (cpSpread, smaShrt, Color.Black, LineStyle.Solid, 1);
    if (Bars.BarInterval > 1) {
      DataSeries diff = smaLong - smaShrt;
      ChartPane cpDiff = CreatePane (25, true, true);
      PlotSeries (cpDiff, diff, Color.Gray, LineStyle.Histogram, 3);
      return;
    }
    PlotSeries (cpSpread, SpreadLong, Color.Green, LineStyle.Dots, 3);
    PlotSeries (cpSpread, SpreadShrt, Color.Red, LineStyle.Dots, 3);
    PlotSeries (cpSpread, UprLong, Color.Green, LineStyle.Solid, 1);
    PlotSeries (cpSpread, LwrShrt, Color.Red, LineStyle.Solid, 1);
    for (int i = 0; i < Data.PeriodBars-1; ++i) {
      UprLong[i] = UprLong[Data.PeriodBars-1];
      LwrShrt[i] = LwrShrt[Data.PeriodBars-1];
      SetSeriesBarColor (i, UprLong, Color.Empty);
      SetSeriesBarColor (i, LwrShrt, Color.Empty);
    }
    int upr = 0; int lwr = 0; int uprlwr = 0;
    for (int i = Data.PeriodBars-1; i < Bars.Count; ++i) {
      if (SpreadLong[i] >= UprLong[i] && SpreadShrt[i] > LwrShrt[i]) {
        SetPaneBackgroundColor (cpSpread, i, Color.LightGreen);
        ++upr;
      } else if (SpreadShrt[i] <= LwrShrt[i] && SpreadLong[i] < UprLong[i]) {
        SetPaneBackgroundColor (cpSpread, i, Color.Pink);
        ++lwr;
      } else if (SpreadLong[i] >= UprLong[i] && SpreadShrt[i]<= LwrShrt[i]) {
        SetPaneBackgroundColor (cpSpread, i, Color.LightYellow);
        ++uprlwr;
      }
    }
    int j = Bars.Count-10;
    AnnotateChart(cpSpread, SpreadLong[j].ToString()
      ,j, SpreadLong[j]+17, Color.Black);
    AnnotateChart(cpSpread, SpreadShrt[j].ToString()
      ,j, SpreadShrt[j]-7, Color.Red);
    k = -20;
    PrintDebug (String.Format ("{0,"+k+"}{1,7} ({2,5:F2}%)"
      ,"Пробоев вверх", upr
      ,100.0 * upr / (Bars.Count - Data.PeriodBars)));
    PrintDebug (String.Format ("{0,"+k+"}{1,7} ({2,5:F2}%)"
      ,"Пробоев вниз", lwr
      ,100.0 * lwr / (Bars.Count - Data.PeriodBars)));
    PrintDebug (String.Format ("{0,"+k+"}{1,7} ({2,5:F2}%)"
      ,"Пробоев вверх и вниз", uprlwr
      ,100.0 * uprlwr / (Bars.Count - Data.PeriodBars)));  

    SpreadMid = ((High + Open) - (Close + Low)) / 2;
    SpreadMid.Description = "SpreadMid";
    DataSeries smaMid = SMA.Series (SpreadMid, Data.PeriodBars);
    smaMid.Description = "SmaMid";
    ChartPane cpMid = CreatePane (25, true, true);
    DrawLabel (cpMid, "Mid");
    PlotSeries (cpMid, SpreadMid, Color.Black, LineStyle.Solid, 1);
    PlotSeries (cpMid, smaMid, Color.Blue, LineStyle.Solid, 1);
    UprMid = smaMid + Data.MinProfit;
    UprMid.Description = "UptMid";
    LwrMid = smaMid - Data.MinProfit;
    LwrMid.Description = "LwrMid";
    PlotSeries (cpMid, UprMid, Color.Green, LineStyle.Solid, 1);
    PlotSeries (cpMid, LwrMid, Color.Red, LineStyle.Solid, 1);
    for (int i = 0; i < Data.PeriodBars-1; ++i) {
      UprMid[i] = UprMid[Data.PeriodBars-1];
      LwrMid[i] = LwrMid[Data.PeriodBars-1];
      SetSeriesBarColor (i, UprMid, Color.Empty);
      SetSeriesBarColor (i, LwrMid, Color.Empty);
    }
    for (int i = Data.PeriodBars-1; i < Bars.Count; ++i) {
      if (SpreadMid[i] > UprMid[i])
        SetPaneBackgroundColor (cpMid, i, Color.LightGreen);
      else if (SpreadMid[i] < LwrMid[i])
        SetPaneBackgroundColor (cpMid, i, Color.Pink);
    }
  } // Prepare()
    
  void SetPeriodBars() {
      if (Bars.BarInterval > 1) { // Arg.PeriodMins) {
      Arg.PeriodMins = Bars.BarInterval;
      Data.PeriodBars = 1;
      return;
    }
    int barsPerMin = 60 * Int32.Parse (
      Bars.Symbol [Bars.Symbol.Length-1].ToString());
    Data.PeriodBars = Arg.PeriodMins * barsPerMin / Bars.BarInterval;
  }
} // class CalendarSpreadTwo
  
class Pos {
  public int Type = 0; // 1 - long, -1 - short
  public int EntryBar, ExitBar;
  public double EntryPrice, ExitPrice;
  public int PosNo = 0;
}  
} // namespace WealthLab.Strategies
Это головной скрипт монитора на QLua для Quik:
-- Мониторим котировки ближнего и дальнего фьючерсов по тикам
Data = { "RIH0", "RIM0" -- дорогой и дешёвый фьючерсы
 ,MsDlt = 200           -- период опроса очереди заявок, мсек
}
  
function OnInit (scriptPath)
dofile ("D:\\BAT\\Lua\\SetPaths64.lua")
Require { qu = "QuikUtil(qu)" } -- lu, qc, tu, wau
ScriptDir, ScriptName = lu.SplitPath (scriptPath)
end -- OnInit()

function OnStop (signal) -- 1 по кнопке Остановить
StopFlag = true          -- 2 при закрытии Quik'а
return 3000 -- Вместо стандартных 5 сек
end -- OnStop()

function main()
dofile (ScriptDir .."OneOf_Lib.lua")
local frame = MakeFrame() -- Неуклюжая идея. Исправить!!!
message (ScriptName ..": Start")
while not StopFlag and frame.HandleTick() do end
message (ScriptName ..": Quit")
end -- main()
А это его вспомогательный dofile:
-- dofile монитора котировок ближнего и дальнего фьючерсов по тикам
-- Константы
local Header =
"<TICKER>;<PER>;<DATE>;<TIME>;<OPEN>;<HIGH>;<LOW>;<CLOSE>;<VOL>"
local per = "1"
local tmBeg, tmEnd = "10000", "184500"
--local tmBeg, tmEnd = "00000", "235000"
-- Параметры: Data.MsDlt
-- Data[1],[2] -- дорогой и дешёвый фьючерсы, "BRG0", "BRH0" и т.п.
local ticker = Data[1] .."-".. Data[2]
-- Общие: Log, ScriptDir С конечным "\", ScriptName Без расширения
local ymd = os.date ("%Y%m%d", os.time())
local sfx = Data.MsDlt == 200 and 5 or
  Data.MsDlt == 500 and 2 or nil
if not sfx then error ("Invalid MsDlt", 2) end
Log = io.open (ScriptDir .."Log\\".. ymd .."_".. ScriptName
 .. sfx ..".csv", "w")
Log:write (Header)

function MakeFrame ()
local ask1, bid1, ask2, bid2, sprd
local frm = Data[1]:sub (1, 2) == "GD" and
     "%s;%s;%s;%s;%.1f;%.1f;%.1f;%.1f;%.2f"
  or Data[1]:sub (1, 2) == "BR" and
     "%s;%s;%s;%s;%.2f;%.2f;%.2f;%.2f;%.3f"
  or "%s;%s;%s;%s;%d;%d;%d;%d;%d" -- GZ, RI, Si, SR
local pre, no = os.time(), 0 -- Ловим начало секунды
local cur = pre
while cur == pre do sleep (1); cur = os.time() end
pre = cur
local m = {}

m.HandleTick = function()
  local tm = os.date ("%H%M%S", cur)
  if tm >= tmEnd then return false end
  if tm >= tmBeg then
    no = no + 1
    ask1 = qu.GetParamNum (qc.SPBFUT, Data[1], qc.OFFER)
    ask2 = qu.GetParamNum (qc.SPBFUT, Data[2], qc.OFFER)
    bid1 = qu.GetParamNum (qc.SPBFUT, Data[1], qc.BID)
    bid2 = qu.GetParamNum (qc.SPBFUT, Data[2], qc.BID)
    sprd = (ask1 + bid1) / 2 - (ask2 + bid2) / 2
    local msg = string.format (frm, ticker, per
      ,os.date ("%Y%m%d", cur), tm
      ,bid1, ask1, bid2, ask2, no)
    Log:write ("\n".. msg)
  end -- if tm >= tmBeg
  sleep (Data.MsDlt)
  cur = os.time()
  if cur > pre then
    Log:flush()
    pre, no = cur, 0
  end
  return true
end -- m.HandleTick()

return m
end -- MakeFrame()
25 Комментариев
  • 3Qu
    08 февраля 2020, 22:51
    Оч хорошо проделанная работа. Возможно, неверен сам подход к снаряду.
    • quant_trader
      10 февраля 2020, 12:02
      3Qu, «Возможно, неверен сам подход к снаряду.»

      У Вас есть положительный опыт торговли этого календарника? Или это тоже только в теории на минутках?
      • 3Qu
        10 февраля 2020, 14:12
        quant_trader, мы же за теорию говорим? В теории это работает. Если у вас не работает — значит неправильная теория.
        • quant_trader
          10 февраля 2020, 16:09
          3Qu, не, я спрашиваю именно практический результат. Значит тут тоже только теория без практики?
          • 3Qu
            10 февраля 2020, 16:22
            quant_trader, я не вижу причин, почему теория не должна работать на практике. Если есть торгуемые контракты на ваших уровнях, почему бы некоторым из них не стать вашими.)
            В опционах ликвидность похуже, но ведь торгуют и не жалуются.
  • Андрей К
    08 февраля 2020, 23:10
    Фишка в том, что 200млсек многовато для такого исследования. Чтобы была надежная доказательная база, дату надо прям по прямым протоколам получать
    • 3Qu
      08 февраля 2020, 23:14
      Андрей К, неправда ваша. Для такого, точнее -подобного, исследования минутных данных вполне достаточно.
      • Андрей К
        08 февраля 2020, 23:16
        3Qu, если вы говорите про минутки вообще, то теперь и у меня появились сомнения на счет правильности вашего топика.

        upd. Хотя прошу прощение. Если ставка по маркету плавает, то между фучами да, ставка тоже поплывет
        • 3Qu
          08 февраля 2020, 23:22
          Андрей К, сомнения вас, возможно и правильные, но и в топике я далеко не все написал. Только саму идею, но не мануал.) Реализации могут быть оч разными.
      • quant_trader
        10 февраля 2020, 16:12
        3Qu, нет. В минутках между закрытием одного инструмента и другого может быть несколько секунд и вся теория по одному месту.
        • 3Qu
          10 февраля 2020, 16:25
          quant_trader, несколько секунд абсолютно ничему не мешают. Вы же HFT хотите.
          • quant_trader
            10 февраля 2020, 19:45
            3Qu, подожду когда у Вас появится практический опыт
            • 3Qu
              10 февраля 2020, 20:07
              quant_trader, вы об этом не узнаете.) Я не обсуждаю свои системы.
      • Андрей К
        08 февраля 2020, 23:20
        Rostislav Kudryashov, это в квике так видно. Квик может легко не показать, как бид/офер за секунду раз 20-30 может поменяться.
      • Дмитрий Овчинников
        09 февраля 2020, 02:14
        Rostislav Kudryashov, 

        привожу график по RTS-3.20 за 1 секунду, за которую было огромное количество возможностей, в том числе и календарного арбитража с RTS-6.20.



        По RTS-3.20 за эту секунду проторговано более 5 тысяч лотов. 
        По RTS-6.20 за этот же период проторговано 11 (одиннадцать!) лотов.
        Где все арбитражеры то?

        • 3Qu
          09 февраля 2020, 22:06
          Дмитрий Овчинников, вообще, арбитражом занимаются немногие, и, в основном, профи. А 11 лотов/с — это оч. не мало. Сколько там в час? А за сессию?
          • Дмитрий Овчинников
            09 февраля 2020, 22:09
            3Qu, 
            это не просто секунда. Это уникальная секунда. Если вы этого не видите на картинке, мне жаль.
            • 3Qu
              09 февраля 2020, 22:14
              Дмитрий Овчинников, не впечатляет. Ну, за 1 с столько же, как за последующие 100. И что это означает? Кому-то захотелось закупиться или запродаться на 5 тыс лотов. Событие вселенского масштаба.))
  • Captain Eugene
    10 февраля 2020, 12:26
    На московской бирже го на календарный спред по прежнему такое же как за сумму го двух фьючерсов?

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн