Перейти к содержанию

Пользовательские инструменты

API пользовательских инструментов позволяет создавать собственные инструменты в cTrader и управлять ими. Эти инструменты могут представлять синтетические активы, внешние наборы данных, производные метрики или полностью офлайн-инструменты. Каждый пользовательский инструмент может быть определен с использованием одного или двух активов и поддерживает полную интеграцию с таймфреймами, графиками, индикаторами, бэктестингом и обновлениями в режиме реального времени.

Ключевые типы и методы для пользовательских инструментов включают:

  • CustomSymbols.Add(name, baseSymbol) или CustomSymbols.Add(name, baseAsset, quoteAsset) для создания нового пользовательского инструмента.
  • CustomSymbol.BarsNeeded для предоставления данных OHLC для инструмента по запросу.
  • CustomSymbol.UpdateQuote(bid, ask) для передачи текущих цен инструменту.
  • CustomBars.AppendBars(), UpdateLastBar() и PrependBars() для динамического управления данными баров. Каждый CustomBar хранит Time, Open, High, Low, Close и Volume.

Кроме того, разработчики могут определять ставки свопа, комиссии, уровни кредитного плеча, настроения, настройки фьючерсов и даже рыночные часы или праздничные дни для пользовательских инструментов. После создания пользовательские инструменты полностью интерактивны и могут просматриваться на графиках или использоваться программно в сиБотах, индикаторах и плагинах.

Совет

Используйте пользовательские инструменты для визуализации внешних данных, моделирования спредов или корреляций, тестирования стратегий на собственных наборах данных или объединения нескольких активов в синтетические инструменты.

Объекты API пользовательских инструментов можно использовать для следующих целей:

Функция или операция Примеры
Моделирование синтетических активов Создание инструмента спреда (например, UKOIL - USOIL)
Создание корзин акций или валют
Визуализация офлайн-наборов данных Загрузка данных CSV для рынков
Построение графиков исторических процентных ставок или экономических индексов
Построение графиков в реальном времени из API Передача внешних цен в режиме реального времени
Потоковая передача рассчитанной справедливой стоимости или метрик риска
Тестирование стратегий на пользовательских данных Бэктестинг на фундаментальных или альтернативных наборах данных
Моделирование устаревших рыночных условий
Генерация синтетических котировок Получение пользовательских цен из существующих инструментов
Внедрение котировок в пользовательские инструменты
Моделирование торговых ограничений Применение пользовательских сессий, праздничных дней, истечения фьючерсов, структуры свопа или уровней кредитного плеча
Визуализация метрик стратегии Построение графика кривой средств, просадки или сигналов в виде ценовых серий для внутристратегического анализа

Базовые операции

Создать новый пользовательский инструмент с базовым инструментом

1
2
3
4
5
var baseSymbol = Symbols.GetSymbol("EURUSD");

var customSymbol = CustomSymbols.Add("MyCustomSymbol1", baseSymbol);
customSymbol.Description = "Synthetic EURUSD Tracker";
customSymbol.UpdateQuote(baseSymbol.Bid, baseSymbol.Ask);

Создать пользовательский инструмент с активами (без базового инструмента)

1
2
3
4
5
var baseAsset = Assets.GetAsset("XAU");
var quoteAsset = Assets.GetAsset("USD");

var customSymbol = CustomSymbols.Add("GoldIndex", baseAsset, quoteAsset);
customSymbol.UpdateQuote(1923.5, 1923.8);

Определить статические свойства инструмента

1
2
3
4
5
6
customSymbol.LotSize = 100000;
customSymbol.PipDigits = 2;
customSymbol.TickDigits = 3;
customSymbol.Commission = 3.5;
customSymbol.SwapLong = -0.2;
customSymbol.SwapShort = 0.1;

Назначить поток котировок (реальный или смоделированный)

1
2
var tracking = Symbols.GetSymbol("GBPUSD");
tracking.Tick += e => customSymbol.UpdateQuote(e.Symbol.Bid, e.Symbol.Ask);

Обработать запрос баров для синтетических данных

1
2
3
4
5
6
customSymbol.BarsNeeded = args =>
{
    var baseBars = MarketData.GetBars(args.CustomBars.TimeFrame, "EURUSD");
    var newBars = baseBars.Select(b => new CustomBar(b.OpenTime, b.Open, b.High, b.Low, b.Close, b.TickVolume));
    args.CustomBars.AppendBars(newBars);
};

Добавить бар в режиме реального времени по тику

1
2
3
4
5
tracking.Tick += _ =>
{
    var last = MarketData.GetBars(TimeFrame.Minute, tracking.Name).LastBar;
    customSymbol.CustomBars.UpdateLastBar(last.Open, last.High, last.Low, last.Close, last.TickVolume);
};

Добавить пользовательскую торговую сессию

1
2
3
4
customSymbol.MarketHours.Sessions.Add(new CustomSymbolTradingSession(
    DayOfWeek.Monday, DayOfWeek.Friday,
    new TimeSpan(8, 0, 0), new TimeSpan(16, 30, 0)
));

Определить настройки фьючерсов

1
2
3
4
5
customSymbol.FuturesSettings = new CustomSymbolFuturesSettings(
    DateTime.UtcNow.AddDays(20),
    DateTime.UtcNow.AddDays(30),
    0.15 // maintenance margin
);

Добавить динамические уровни кредитного плеча

1
2
customSymbol.DynamicLeverage.Add(new CustomSymbolLeverageTier(100000, 100));
customSymbol.DynamicLeverage.Add(new CustomSymbolLeverageTier(500000, 50));

Создать и добавить пользовательский период

1
2
3
4
5
6
7
var customTF = TimeFrameManager.Custom.Add("MyCustomH1");

customTF.BarsNeeded = args =>
{
    var hourly = MarketData.GetBars(TimeFrame.Hour, args.CustomBars.Symbol.Name);
    args.CustomBars.AppendBars(hourly.Select(b => new CustomBar(b.OpenTime, b.Open, b.High, b.Low, b.Close, b.TickVolume)));
};

Импортировать данные из CSV

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var lines = File.ReadAllLines("data.csv");

var bars = lines.Skip(1).Select(line =>
{
    var parts = line.Split(',');
    return new CustomBar(DateTime.Parse(parts[0]), 
                         double.Parse(parts[1]), double.Parse(parts[2]), 
                         double.Parse(parts[3]), double.Parse(parts[4]), 
                         int.Parse(parts[5]));
});

customSymbol.BarsNeeded = args => args.CustomBars.AppendBars(bars);

Удалить пользовательский инструмент

1
2
var cs = CustomSymbols.Get("MyCustomSymbol1");
CustomSymbols.Remove(cs);

Примеры практической интеграции

Отслеживать фундаментальные данные с течением времени

Отображайте макроэкономические индикаторы, такие как ИПЦ, уровень безработицы или ВВП, в виде синтетических баров OHLC. Этот подход позволяет накладывать стратегию, анализировать расхождения и отслеживать исторические паттерны с использованием структурированных экономических данных.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var macroSymbol = CustomSymbols.Add("US_MacroIndex", Assets.GetAsset("USD"), Assets.GetAsset("USD"));
macroSymbol.BarsNeeded = args =>
{
    var csvData = LoadCustomCsv("us_macro.csv"); // contains OpenTime, Open, High, Low, Close, Volume
    args.CustomBars.AppendBars(csvData.Select(row => new CustomBar(
        DateTime.Parse(row[0]),
        double.Parse(row[1]),
        double.Parse(row[2]),
        double.Parse(row[3]),
        double.Parse(row[4]),
        int.Parse(row[5])
    )));
};

Создание взвешенной корзины активов

Объедините несколько акций в пользовательский инструмент, отражающий взвешенный портфель. Такая настройка позволяет отслеживать эффективность, применять индикаторы и проводить бэктестинг стратегий на синтетическом индексе акций, построенном из выбранных компонентов.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
var customIndex = CustomSymbols.Add("MyAssetBasket", Assets.GetAsset("USD"), Assets.GetAsset("USD"));
customIndex.BarsNeeded = args =>
{
    var eurusdBars = MarketData.GetBars(TimeFrame.Daily, "EURUSD");
    var gbpusdBars = MarketData.GetBars(TimeFrame.Daily, "GBPUSD");
    var usdjpyBars = MarketData.GetBars(TimeFrame.Daily, "USDJPY");

    var indexBars = Enumerable.Range(0, Math.Min(eurusdBars.Count, Math.Min(gbpusdBars.Count, usdjpyBars.Count)))
        .Select(i =>
        {
            var time = eurusdBars[i].OpenTime;
            var weightedClose = eurusdBars[i].Close * 0.4 + gbpusdBars[i].Close * 0.35 + usdjpyBars[i].Close * 0.25;

            return new CustomBar(time, weightedClose, weightedClose, weightedClose, weightedClose, 0);
        });

    args.CustomBars.AppendBars(indexBars);
};

Отслеживание разницы цен на сырьевые товары

Рассмотрите возможность создания пользовательского инструмента, представляющего ценовой спред между золотом и серебром (XAUUSD - XAGUSD). Этот пользовательский инструмент может помочь в стратегиях торговли спредами, обнаружении дивергенций и межрыночном анализе драгоценных металлов.

Анализируя разницу в движении цен между золотом и серебром, трейдеры могут определить относительную силу, потенциальные арбитражные возможности или хеджировать одну позицию против другой.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
var spreadSymbol = CustomSymbols.Add("Gold_Silver_Spread", Assets.GetAsset("USD"), Assets.GetAsset("USD"));
spreadSymbol.BarsNeeded = args =>
{
    var gold = MarketData.GetBars(TimeFrame.Hour, "XAUUSD");
    var silver = MarketData.GetBars(TimeFrame.Hour, "XAGUSD");

    var spread = gold.Zip(silver, (g, s) => new CustomBar(
        g.OpenTime,
        g.Close - s.Close,
        g.Close - s.Close,
        g.Close - s.Close,
        g.Close - s.Close,
        g.TickVolume + s.TickVolume
    ));

    args.CustomBars.AppendBars(spread);
};

Потоковая передача символа спреда на валютном рынке в реальном времени

Создайте синтетический инструмент в реальном времени, вычитая цены двух валютных пар.
Этот пользовательский инструмент позволяет строить графики и торговать спредом напрямую, поддерживая стратегии возврата к среднему, визуальное отслеживание и хеджирование на основе спреда.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
private CustomSymbol _eurGbpSpread;
private Symbol _eurusd, _gbpusd;

protected override void OnStart()
{
    _eurusd = Symbols.GetSymbol("EURUSD");
    _gbpusd = Symbols.GetSymbol("GBPUSD");

    _eurGbpSpread = CustomSymbols.Add("EUR‑GBP Spread",
                                      _eurusd.QuoteAsset,  // both legs already trade in USD
                                      _eurusd.QuoteAsset);

    // propagate tick updates
    _eurusd.Tick  += OnLegTick;
    _gbpusd.Tick  += OnLegTick;
}

private void OnLegTick(SymbolTickEventArgs _)
{
    var mid = _eurusd.Bid - _gbpusd.Bid;        // naïve spread
    _eurGbpSpread.UpdateQuote(mid, mid + 0.00001); // 0.1 pip synthetic spread
}