В процессе загрузки ресурсов... загрузка...

ФМЗ: Стратегия для количественной платформы

Автор:Трава, Создано: 2019-08-19 15:54:35, Обновлено: 2021-06-08 16:14:57

[TOC] Прежде чем выучить этот урок, вы должны научиться.FMZ изобретатели используют квантовую платформу для введенияиФМЗ количественная платформа стратегии написания первичных учебниковИмеет хорошее знание языков программирования.В начальном уроке рассматриваются наиболее часто используемые функции, но есть много других функций и функций, которые не были представлены, и которые не будут охвачены в этом уроке.После изучения этого учебника вы сможете написать более свободную и более индивидуальную стратегию, а платформа FMZ - это всего лишь инструмент.

Доступ к исходным данным биржи

Для сохранения единообразия поддержка API для отдельных бирж неполная. Например, для получения K-линий обычно доступно количество K-линий или время начала, а для FMZ платформа является фиксированной, некоторые платформы поддерживают объемные заказы, FMZ не поддерживает, и т. Д. Поэтому необходим способ прямого доступа к данным биржи.Для открытых интерфейсов (например, рынков)HttpQuery, для добавления близких слов (включая информацию об аккаунте), необходимо использоватьIOКонкретные параметры передачи, также см. соответствующую документацию API биржи.InfoПоле возвращает первоначальную информацию, но все еще не может решить проблему с неподдержкой интерфейса.

GetRawJSON ((()

Возвращает первоначальный контент (стринг) последнего запроса REST API, который можно использовать для самостоятельного анализа расширенной информации.

function main(){
    var account = exchange.GetAccount() //the account doesn't contain all data returned by the request
    var raw = JSON.parse(exchange.GetRawJSON())//raw data returned by GetAccount()
    Log(raw)
}

HttpQuery ((() для доступа к открытому интерфейсу

Доступ к открытому интерфейсу, используемому JsHttpQueryPython может использовать свои собственные пакеты, такие как:urllibилиrequests

HttpQuery является методом GET по умолчанию, но также поддерживает больше функций.

var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo)
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
var kline = JSON.parse(HttpQuery("https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596"))

Примеры использования запросов в Python

import requests
resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596')
data = resp.json()

Функция IO получает доступ к соединительному отверстию

Для интерфейсов, требующих подписи API-KEY, можно использовать функцию IO, пользователю нужно только обратить внимание на ввод параметров, а конкретный процесс подписи будет выполняться нижним слоем.

Платформа FMZ в настоящее время не поддерживает BitMEX.

  • На странице с инструкциями по API BitMEX:https://www.bitmex.com/api/explorer/
  • На сайте BitMEX можно найти:https://www.bitmex.com/api/v1/orderПример:POST; поскольку FMZ уже установил внутренний адрес корня, нужно просто ввести "/api/v1/order".
  • Параметрыsymbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop

Конкретный код:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
//也可以直接传入对象
var id = exchange.IO("api", "POST", "/api/v1/order", "", JSON.stringify({symbol:"XBTUSD",side:"Buy",orderQty:1,stopPx:4000,ordType:"Stop"}))

Больше примеров ИО:https://www.fmz.com/bbs-topic/3683

Использование веб-сокета

По сути, все цифровые валютные биржи поддерживают websocket для отправки, а некоторые поддерживают websocket для обновления учетной информации. По сравнению с rest API, websocket обычно имеет низкую задержку, высокую частоту, не ограничивается частотой rest API платформы.

В статье будут рассмотрены основные аспекты квантовой платформы FMZ, использования языка JavaScript, подключения к диалоговой функции, встроенной в платформу, описания и параметры в документации, поиск Диала, для реализации различных функций, которая была обновлена несколько раз, а также стратегии для управления событиями на основе WSS, а также проблемы с подключением к нескольким биржам. Python также может использовать диалоговой функцию и соответствующую библиотеку.

1.websocket连接

Обычно можно напрямую подключиться, например, для получения тикеров:

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")

Для возвращаемых данных формат компрессии, необходимый при соединении, указан, compress указывает формат компрессии, mode представляет собой отправку возвращаемых данных, требующих сжатия, например, при соединении OKEX:

var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")

Функция Dial поддерживает переключение, выполненное базовым языком Go, обнаруживаемое соединение отключается и пересоединяется, очень удобно, рекомендуется использовать для содержания запрошенных данных, которые уже находятся в url, как в примере, который мы только что представили. Для тех, кому нужно отправить сообщение, можно самостоятельно поддерживать механизм переключения.

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")

Подпишитесь на сообщения wss, некоторые запросы обмена находятся в url, а также некоторые каналы, которые требуют отправки подписки, такие как coinbase:

client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')

2.加密接口连接

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

    //火币期货推送例子
    var ACCESSKEYID = '你的火币账户的accesskey'
    var apiClient = Dial('wss://api.hbdm.com/notification|compress=gzip&mode=recv')
    var date = new Date(); 
    var now_utc =  Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    var utc_date = new Date(now_utc)
    var Timestamp = utc_date.toISOString().substring(0,19)
    var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent(Timestamp)
    var signature = exchange.HMAC("sha256", "base64", quest, "{{secretkey} }") //去掉}}之间的多余空格
    auth = {op: "auth",type: "api",AccessKeyId: ACCESSKEYID, SignatureMethod: "HmacSHA256",SignatureVersion: "2", Timestamp: Timestamp, Signature:encodeURI(signature)}
    apiClient.write(JSON.stringify(auth))
    apiClient.write('{"op": "sub","cid": "orders","topic": "orders.btc'}')
    while (true){
        var data = datastream.read()
        if('op' in data && data.op == 'ping'){
            apiClient.write(JSON.stringify({op:'pong', ts:data.ts}))
        }
    }
    
    //币安推送例子,注意需要定时更新listenKey
    var APIKEY = '你的币安accesskey'
    var req = HttpQuery('https://api.binance.com/api/v3/userDataStream',{method: 'POST',data: ''},null,'X-MBX-APIKEY:'+APIKEY);
    var listenKey = JSON.parse(req).listenKey;
    HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'DELETE',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
    listenKey = JSON.parse(HttpQuery('https://api.binance.com/api/v3/userDataStream','',null,'X-MBX-APIKEY:'+APIKEY)).listenKey;
    var datastream = Dial("wss://stream.binance.com:9443/ws/"+listenKey+'|reconnect=true',60);
    var update_listenKey_time =  Date.now()/1000;
    while (true){
        if (Date.now()/1000 - update_listenKey_time > 1800){
            update_listenKey_time = Date.now()/1000;
            HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'PUT',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
        }
        var data = datastream.read()
    }

    //BitMEX推送例子
    var APIKEY = "你的Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")//secretkey在执行时自动替换,不用填写
    var client = Dial("wss://www.bitmex.com/realtime", 60)
    var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
    var pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while (true) {
        bitmexData = client.read()
        if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
            Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
            pos = parseInt(bitmexData.data[0].currentQty)
        }
    }

3.websocket读取

Как правило, в процессе цикла смерти можно читать и читать, и код выглядит так:

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg) //把json字符串解析为可引用的object
// 处理data数据
    }
}

wss передает данные очень быстро, нижний слой Go откладывает все данные в очередь, и когда программа вызывает read, она возвращается обратно; а операции, такие как загрузка диска, приводят к задержке, что может привести к накоплению данных. Для передачи транзакций, рассылки счетов, рассылки глубины, мы нуждаемся в исторических данных, а для рыночных данных мы в большинстве случаев интересуемся только последними, не интересуемся историческими данными.

read()Если параметры не добавлены, возвращается самый старый данный, а когда нет данных, блокируется до возвращения.client.read(-2)Возвращение немедленно последнего данного, но возвращение null, когда больше нет данных, требует суждения и повторного ссылки.

В зависимости от того, как обращаться со старыми данными в кэше, а также от того, блокируются ли они при отсутствии данных, read имеет различные параметры, которые, как показано ниже, кажутся сложными, но делают программу более гибкой.img

4.连接多个交易所websocket

Для такого случая в процедуре, очевидно, нельзя использовать простой read ((), поскольку одна биржа будет блокировать ожидание сообщения, в то время как другая биржа не будет принимать новое сообщение.

    function main() {
        var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        var coinbase = Dial("wss://ws-feed.pro.coinbase.com", 60)
        coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
        while (true) {
            var msgBinance = binance.read(-1) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // 此时币安有数据返回
            }
            if(msgCoinbase){
                // 此时coinbase有数据返回
            }
            Sleep(1) // 可以休眠1ms
        }
    }

5.断线重连问题

Эта часть обработки является более проблематичной, поскольку перемещение данных может быть прервано, или задержка перемещения чрезвычайно высока, даже если получать сердцебиение не означает, что данные все еще перемещаются, можно установить интервал событий, если не будет получено обновления, перезагрузиться, и лучше провести некоторое время и сравнить результаты возвращения rest, чтобы увидеть, является ли данные точными. Для таких особых случаев, как Bitcoin, можно установить автоматическое перезагрузку.

6.使用websocket的一般程序框架

Поскольку уже использовались данные push, программа, естественно, должна быть написана как event-driven, обратите внимание на частое push, чтобы не использовать слишком много запросов, что приведет к закрытию.

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//这里即限制了2s内只交易一次
            tradeTime = Date.now()
            //交易逻辑
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//这里即限制了5s内只获取账户一次
            accountTime = Date.now()
            return exchange.GetAccount()
        }
    }
    function main() {
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true");
        while (true) {
            var msg = client.read()
            var data = JSON.parse(msg)
            var account = GetAccount()
            trade(data)
        }
    }

7.总结

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

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

Многопроводные параллели

JavaScript может быть реализован с помощью Go-функции, а Python может использовать соответствующую многострочную библиотеку.

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

var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()

При наличии задержки при одном запросе rest API, предположим, 100 мс, то время, необходимое для получения глубины дважды, фактически различается. Если требуется больше посещений, проблемы с задержкой будут более заметны, что повлияет на выполнение стратегии.

JavaScript не имеет большого количества потоков, поэтому в нижнем слое используется функция Go, которая решает эту проблему.GetDepth,GetAccountИ так далее.IOНапример:exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders))Однако из-за механизма проектирования реализация сложна.

var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果 
var depthB = b.wait()

В большинстве простых случаев написание такой политики без проблем. Но обратите внимание, что каждый цикл политики повторяет этот процесс, и промежуточные переменные a, b на самом деле являются временными помощниками. Если у нас очень много параллельных задач, необходимо дополнительно записать взаимоотношения между a и depthA, b и depthB, что становится более сложным, когда наша параллельная задача не определена.

function G(t, ctx, f) {
    return {run:function(){
        f(t.wait(1000), ctx)
    }}
}

Мы определяем функцию G, где t - это функция Go, которую мы собираемся выполнить, ctx - это контекст записи программы, f - это функция с конкретным назначением.

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

var Info = [{depth:null, account:null}, {depth:null, account:null}] //加入我们需要获取两个交易所的深度和账户,跟多的信息也可以放入,如订单Id,状态等。
var tasks = [ ] //全局的任务列表

function produce(){ //下发各种并发任务
  //这里省略了任务产生的逻辑,仅为演示
  tasks.push({exchange:0, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:1, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:0, ret:'sellID', param:['Buy', Info[0].depth.Asks[0].Price, 10]})
  tasks.push({exchange:1, ret:'buyID', param:['Sell', Info[1].depth.Bids[0].Price, 10]})
}
function worker(){
    var jobs = []
    for(var i=0;i<tasks.length;i++){
        var task = tasks[i]
        jobs.push(G(exchanges[task.exchange].Go.apply(this, task.param), task, function(v, task) {
                    Info[task.exchange][task.ret] = v //这里的v就是并发Go函数wait()的返回值,可以仔细体会下
                }))
    }
    _.each(jobs, function(t){
            t.run() //在这里并发执行所有任务
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // 发出交易指令
        worker()        // 并发执行
        Sleep(1000)
    }
}

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

Диаграмма функции Chart

Учебное пособие "Введение диаграмм" рекомендует библиотеку диаграмм, которая в большинстве случаев может удовлетворить потребности. Если требуется дальнейшая настройка, можно напрямую работать с объектами Chart.

Chart({…})Внутренние параметры - это объекты HighStock и HighCharts, просто добавленный дополнительный параметр.__isStockДля определения того, является ли HighStock; HighStock более сосредоточен на графике временной последовательности, поэтому более часто используется. FMZ в основном поддерживает базовые модули HighCharts и HighStock, но не поддерживает дополнительные модули.

Пример HighCharts:https://www.highcharts.com/demoПример HighStock:https://www.highcharts.com/stock/demoНапример, на FMZ можно переместить файлы, содержащие коды из этих примеров.

Можно вызвать add (([series index ((e.g. 0, data]) для добавления данных к серии указанного индекса, вызвать reset (()) для очистки данных графика, reset может иметь цифровой параметр, указывающий зарезервированные строки. Поддерживает отображение нескольких графов, при настройке нужно просто ввести параметры массива, такие как: var chart = Chart (([{...}, {...}, {...}), например, граф один имеет две серии, граф один имеет серию, граф трисерии, тогда add при указании серии с 01 серия ID представляет данные двух серий из графика 1, когда add при указании серии ID 2 указывает на данные первой серии из графика 2, при указании серии 3 указывает на данные первой серии из графика 3;

Вот один конкретный пример:

var chart = { // 这个 chart 在JS 语言中 是对象, 在使用Chart 函数之前我们需要声明一个配置图表的对象变量chart。
    __isStock: true,                                    // 标记是否为一般图表,有兴趣的可以改成 false 运行看看。
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // 缩放工具
    title : { text : '差价分析图'},                       // 标题
    rangeSelector: {                                    // 选择范围
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    xAxis: { type: 'datetime'},                         // 坐标轴横轴 即:x轴, 当前设置的类型是 :时间
    yAxis : {                                           // 坐标轴纵轴 即:y轴, 默认数值随数据大小调整。
        title: {text: '差价'},                           // 标题
        opposite: false,                                // 是否启用右边纵轴
    },
    series : [                                          // 数据系列,该属性保存的是 各个 数据系列(线, K线图, 标签等..)
        {name : "line1", id : "线1,buy1Price", data : []},  // 索引为0, data 数组内存放的是该索引系列的 数据
        {name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}, // 索引为1,设置了dashStyle : 'shortdash' 即:设置 虚线。
    ]
};
function main(){
    var ObjChart = Chart(chart);  // 调用 Chart 函数,初始化 图表。
    ObjChart.reset();             // 清空
    while(true){
        var nowTime = new Date().getTime();   // 获取本次轮询的 时间戳,  即一个 毫秒 的时间戳。用来确定写入到图表的X轴的位置。
        var ticker = _C(exchange.GetTicker);  // 获取行情数据
        var buy1Price = ticker.Buy;           // 从行情数据的返回值取得 买一价
        var lastPrice = ticker.Last + 1;      // 取得最后成交价,为了2条线不重合在一起 ,我们加1
        ObjChart.add([0, [nowTime, buy1Price]]); // 用时间戳作为X值, 买一价 作为Y值 传入 索引0 的数据序列。
        ObjChart.add([1, [nowTime, lastPrice]]); // 同上。
        Sleep(2000);
    }
}

Пример использования графической планировки:https://www.fmz.com/strategy/136056

Прогрессивность

Начальное повторение Python

Например, в Китае, в Китае, в Китае.https://github.com/fmzquant/backtest_python

Установка

В командной строке введите следующую команду:

pip install https://github.com/fmzquant/backtest_python/archive/master.zip

Простой пример

Параметры реверсии устанавливаются в виде комментариев в начале кода стратегии, в частности, см. В интерфейсе редактора стратегии FMZ.

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"OKEX","currency":"LTC_BTC","balance":3,"stocks":0}]
'''
from fmz import *
task = VCtx(__doc__) # initialize backtest engine from __doc__
print exchange.GetAccount()
print exchange.GetTicker()
print task.Join() # print backtest result

Проверка

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

# !/usr/local/bin/python
# -*- coding: UTF-8 -*-

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD","balance":10000,"stocks":3}]
'''

from fmz import *
import math
import talib

task = VCtx(__doc__) # initialize backtest engine from __doc__

# ------------------------------ 策略部分开始 --------------------------

print exchange.GetAccount()     # 调用一些接口,打印其返回值。
print exchange.GetTicker()

def adjustFloat(v):             # 策略中自定义的函数
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # 具体的策略代码


def main():
    InitAccount = GetAccount()
    while True:
        onTick()
        Sleep(1000)

# ------------------------------ 策略部分结束 --------------------------

try:
    main()                     # 回测结束时会 raise EOFError() 抛出异常,来停止回测的循环。所以要对这个异常处理,在检测到抛出的异常后调用 task.Join() 打印回测结果。
except:
    print task.Join()         

Настройка обратной проверки

exchange.SetData ((arr), переключается на источники обратной проверки с использованием пользовательских K-линейных данных; аргумент arr, это элемент, который является массивом данных K-линейных столбцов (т. е. массив K-линейных данных, который временно поддерживает только обратную проверку JavaScript).

В матрицах arr формат данных для отдельных элементов:

[
    1530460800,    // time     时间戳
    2841.5795,     // open     开盘价
    2845.6801,     // high     最高价
    2756.815,      // low      最低价
    2775.557,      // close    收盘价
    137035034      // volume   成交量
]

Источники данных могут быть введены в библиотеку типа шаблона.

function init() {                                                          // 模板中的 init 初始化函数会在加载模板时,首先执行,确保 exchange.SetData(arr) 函数先执行,初始化,设置数据给回测系统。
    var arr = [                                                            // 回测的时候需要使用的K线数据
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // 时间最早的一根 K线柱 数据
        ... ,                                                              // K线数据太长,用 ... 表示,数据此处省略。
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // 时间最近的一根 K线柱 数据
    ]
    exchange.SetData(arr)                                                  // 导入上述 自定义的数据
    Log("导入数据成功")
}

Примечание: необходимо, чтобы при инициализации в первую очередь были введены пользовательские данные (т. е. данные, установленные функцией exchange.SetData), и пользовательские K-линейные циклы должны соответствовать базовым K-линейным циклам, установленным на странице ретроспекции, то есть пользовательские K-линейные данные, время одного K-линия составляет 1 минуту, то пользовательские K-линейные циклы, установленные на странице ретроспекции, также должны быть установлены на 1 минуту.

Используйте биржи, не поддерживаемые FMZ

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

exchange.IO("base", "http://api.huobi.pro") 
//http://api.huobi.pro为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全

Не все биржи поддерживают FMZ, но платформа предоставляет доступ к общим протоколам.

  • Затем вы пишете код для доступа к бирже, и программа создает сетевой сервис.
  • Добавить биржу на платформе FMZ, указать адрес и порт сетевого сервиса.
  • Когда хранитель работает на физическом диске биржи с общим протоколом, API-доступ в политике отправляется в общий протокол.
  • Общие протоколы посещают биржи по запросу и возвращают результаты хранителям.

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

В частности:https://www.fmz.com/bbs-topic/1052Примеры общих протоколов Python:https://www.fmz.com/strategy/101399

Создание собственной платформы для количественного измерения

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

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

Быть партнером FMZ

Продвижение класса в облаке

Рынок торговли цифровыми валютами все больше привлекает внимание количественных трейдеров из-за его специфики. Фактически, программируемые сделки уже являются основным направлением цифровых валют, а стратегии хеджирования и т. д. постоянно отсутствуют на рынке.www.fmz.comВ течение четырех лет мы помогали тысячам новичков перейти к количественным операциям. Этот курс стоит всего 20 долларов и предназначен для начинающих.

РаспространениеКурсы по количественному обмену цифровыми валютами в классах NetEase CloudНапример, вы можете загрузить свой курс на веб-сайте и поделиться ссылкой на курс. Если вы хотите, чтобы другие люди зарегистрировались и купили курс через эту ссылку, вы получите 50% от общего раздела в 10 юаней.

Продвижение возобновления работы

Потребители нажимают на рекламные ссылки и загружаются в течение полугода после регистрации, и мы возвращаем комиссию в соответствии с действительной суммой в действительном заказе. Комиссию возвращают в виде баллов в счет рекламодателя, пользователи могут обменять баланс счета изобретателя в соотношении 10:1, а также могут в дальнейшем обменять баллы в обмен на изобретателя.https://www.fmz.com/bbs-topic/3828

ФМЗ - квантовая платформа для предприятий

Полный сайт FMZ может быть развернут на собственном сервере предприятия или команды, чтобы обеспечить полный контроль и настройку функций. Сайт FMZ достиг высокой доступности и безопасности после использования и проверки около 100 000 пользователей, что позволяет экономить время и затраты на количественные команды и предприятия.

Городская система

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

Программы бирж

Изобретательская технологическая торговая система использует технологию съемки в памяти, скорость обработки заказов до 2 млн. штук/сек. Это гарантирует отсутствие каких-либо задержек и отключений. Она может поддерживать бесперебойную и стабильную работу биржи с числом онлайн-пользователей более 20 млн. Система имеет многоуровневую, многоклассовую архитектуру, которая гарантирует безопасность, стабильность и легкость расширения.


Больше

БбббвввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввввМожно ли в группу?

Майкео"Бог травы, боевые искусства!"

Трава`` // Пример торгового фьючерса var ACCESSKEYID = 'доступный ключ к вашему токену' var apiClient = Dial (('wss://api.hbdm.com/notification в компрессе=gzip&mode=recv') var date = new Date ((); var now_utc = Date.UTC ((date.getUTCFullYear ((), date.getUTCMonth ((), date.getUTCDate ((), date.getUTCHours ((), date.getUTCMinutes ((), date.getUTCSeconds (())); var utc_date = new Date ((now_utc)) var Timestamp = utc_date.toISOSstring (().substring ((0,19)) var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent ((Timestamp) +'SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' +'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' +'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' +'SignatureMethod=2&Timestamp=2&SignatureMethod=2&SignatureMethod=2&SignatureMethod=2&SignatureMethod=2&S var signature = exchange.HMAC (("sha256", "base64", quest, "{{secretkey}}") ``

Дивизия БитПожалуйста, расскажите, что если веб-сокет подключается к подписной базе, то получать данные базы можно с помощью функции read ((), верно? Если использовать exchange.GetTicker ((), то не извлекать данные из локального кэша, а запускать запрос rest, чтобы вернуть данные, верно? Только токеном поддерживается изменение способа принятия рынка через exchange.IO (("websocket")), а затем exchange.GetTicker (() и exchange.GetDepth (()) перестают запрашивать данные от остальных бирж, а получают данные из уже полученных подписок на рынке, которые существуют в локальном буфере. Я понимаю, да?

ТраваПродолжайте следовать рекомендациям

- Ясно.Просим подтвердить, что в данный момент в группе телеграмм FMZ сообщается:

ШальтиэльХорошо.

ТраваДа, лучше, чтобы все веб-сокеты использовали Dial для более интуитивного управления.