[TOC] Для начала нужно выучить этот урок.Введение в квантовую платформу разработчика FMZиПервоначальный учебник по стратегии квантовой платформы FMZЯвляясь профессионалом в программировании, я не знаю ни одного языка программирования, на котором бы я работал.В начальном руководстве описываются наиболее часто используемые функции, но есть много других функций и возможностей, которые не будут рассмотрены в данном руководстве. Посмотрите документацию API платформы, чтобы узнать больше.После изучения этого учебника вы сможете писать более свободные, более индивидуальные стратегии, а платформа FMZ - это всего лишь инструмент.
Платформа FMZ упакована для всех поддерживаемых бирж, для сохранения единства поддержка API для отдельных бирж не является полной. Как правило, количество или начальное время K-линий может быть передано, например, для получения K-линий, в то время как платформа FMZ является фиксированной, некоторые платформы поддерживают оптовые заказы, FMZ не поддерживает и т. Д. Поэтому необходим способ прямого доступа к данным биржи.Для открытого интерфейса (если это возможно) можно использоватьHttpQueryДля того, чтобы получить доступ к данным счета, необходимо использовать:IO。Конкретные параметры ввода, также обратитесь к соответствующей документации API биржи.InfoПоле возвращает исходную информацию, но все еще не может решить проблему не поддерживаемого интерфейса.
Возвращает исходное содержимое последней 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)
}
Доступ к открытому интерфейсу, используемому в JsHttpQueryPython может самостоятельно использовать соответствующие пакеты, такие как:urllibилиrequests。
HttpQuery по умолчанию является методом GET, а также поддерживает дополнительные функции, см. документацию API.
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()
Для интерфейсов, требующих подписи API-KEY, можно использовать функцию IO, пользователю нужно только обратить внимание на параметры ввода, а конкретный процесс подписания будет выполнен нижним уровнем.
Платформа FMZ в настоящее время не поддерживает стоп-оферты BitMEX, реализуемые через IO, следуя следующим шагам:
https://www.bitmex.com/api/explorer/。https://www.bitmex.com/api/v1/orderМетодикаPOST。 Поскольку FMZ уже указал внутренний root-адрес, достаточно ввести “/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"}))
Более подробные примеры IO: https://www.fmz.com/bbs-topic/3683
В основном все криптовалютные биржи поддерживают отправку websocket, некоторые биржи поддерживают обновление информации об учетных записях websocket. По сравнению с rest API, websocket, как правило, имеет низкую задержку, высокую частоту, не ограничивается частотой платформы rest API и т. Д.
Эта статья будет посвящена в основном квантовой платформе FMZ Inventors, использующей язык JavaScript, использующей встроенную в платформу функцию Dial для подключения, описание и параметры в документации, поиск Dial, которая была несколько раз обновлена для реализации различных функций, эта статья будет охватывать это, а также расскажет о стратегии, основанной на событиях на основе wss, и о проблемах подключения к мультибиржам.
Как правило, это прямое подключение, например, для получения тикеров безопасности:
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
Для возвращенных данных, которые должны быть сжаты, нужно указать, что они должны быть сжаты в соединении, и, чтобы сжать, нужно указать, что они должны быть сжаты в соединении, и, чтобы отправить возвращенные данные, mode означает, что они должны быть сжаты, например, в соединении OKEX:
var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
Функция Dial поддерживает повторное соединение, выполняется языком Go, обнаруживается разрыв соединения и повторное соединение, удобное для запрошенных данных, которые уже есть в url, как в случае с Binance. Рекомендуется использовать. Для тех, кто нуждается в отправке заказных сообщений, можно самостоятельно поддерживать механизм повторного соединения.
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")
Некоторые биржи просят подписаться на новости в url, а также на каналы, которые сами должны подписаться, например, на Coinbase:
client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
Как правило, используется websocket для чтения, но также может использоваться для получения заказов, отправки учетных записей, такая отправка зашифрованных данных иногда может иметь большие задержки, поэтому следует использовать с осторожностью. Поскольку методы шифрования более сложны, здесь приведены несколько примеров для справки. Обратите внимание, что требуется только AccessKey, который можно установить в качестве параметров политики, например, если требуется SecretKey, используйте скрытый вызов функции exchange.HMAC, чтобы обеспечить безопасность.
//火币期货推送例子
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)
}
}
Код, который обычно читается в мертвом цикле, выглядит следующим образом:
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 имеет различные параметры, которые, как показано ниже, кажутся сложными, но позволяют программе быть более гибкой.

Для таких случаев в процедуре явно не может использоваться простое 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
}
}
Эта часть обработки является более проблематичной, потому что передача данных может быть прервана или передача может быть очень задержена, даже если получать сердцебиение, это не означает, что данные все еще передаются. Можно установить интервал событий, пересоединиться, если интервал не будет обновлен, и лучше сравнить результаты с остальным возвратом через некоторое время, чтобы увидеть, является ли данные точными.
Поскольку уже используются push-данные, программа естественно должна быть написана в виде драйвера событий, обратите внимание, что 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)
}
}
Способы подключения веб-сокетов, способы передачи данных, подписный контент и формат данных часто различаются между различными биржами, поэтому платформы не упаковываются и требуют самостоятельного подключения с помощью функции Dial. В этой статье рассматриваются некоторые основные меры предосторожности.
PS. Несмотря на то, что некоторые биржи не предоставляют веб-сокеты, при посещении веб-сайта, используя настройки, вы обнаружите, что они используют веб-сокетный проталкивание, и если вы изучите их, вы обнаружите, что они используют формат подписки и формат возвращения.
JavaScript может реализовываться параллельно с помощью функции Go, а Python может использовать соответствующую многопоточную библиотеку.
При реализации количественной стратегии, во многих случаях, параллельное выполнение может снизить эффективность задержки. Например, для фиксированного диска стратегии хеджирования требуется получить глубину двух монет, последовательность выполнения кода следующая:
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
При запросе REST API есть задержка. Предположим, что она составляет 100 мс. Тогда время получения глубины дважды на самом деле отличается. Если требуется больше доступа, проблема задержки будет более заметной, что повлияет на выполнение стратегии.
Поскольку JavaScript не имеет многопотоков, то в основе этого лежит функция Go, которая может быть использована для API, требующих доступа к сети, например: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 и глубиной A, а также b и глубиной B. Когда наши параллельные задачи неопределенны, ситуация становится более сложной. Поэтому мы хотим реализовать функцию: при написании параллельного кода Go одновременно привязывать переменную, и когда возвращается результат параллельного выполнения, результат автоматически присваивается переменной, тем самым устраняя промежуточные переменные и делая программу более лаконичный. Конкретная реализация выглядит следующим образом:
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)
}
}
Кажется, что мы реализовали только простую функцию, пройдя множество шагов, но на самом деле сложность кода значительно упростилась. Нам нужно заботиться только о том, какие задачи должна генерировать программа, и worker( ) программа автоматически выполнит их одновременно и вернет соответствующие результаты. Гибкость значительно улучшена.
Начальный урок введение в графики является рекомендуемой библиотекой графических графиков, которая в большинстве случаев может удовлетворить потребности. Если требуется дальнейшая настройка, можно непосредственно обращаться с объектами диаграмм.
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 индекс ((например 0), данные]) добавляет данные в указанный индекс серии, вызывает reset ((() очищает графические данные, reset может быть с цифровым параметром, указывая сохраненное число строк. Поддерживает отображение нескольких графиков, при конфигурации необходимо только ввести элементы диаграммы, например: var chart = Chart ((([{…}, {…}, {…}]), например, если в графике A есть две серии, в графике B - одна серия, а в графике C - одна серия, то при add указать 0 и 1 в последовательности 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
На сайте http://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-линия имеет продолжительность 1 минуту, то и базовый K-линейный цикл, установленный в отсчете, должен быть установлен на 1 минуту.
Если API не поддерживаемой биржи и API поддерживаемой биржи полностью совпадает, только базовый адрес отличается, то поддержка может быть осуществлена путем переключения базового адреса. В частности, для добавления биржи выберите поддерживаемую биржу, но заполните API-KEY для не поддерживаемой биржи, переключите базовый адрес в стратегии с помощью IO, например:
exchange.IO("base", "http://api.huobi.pro")
//http://api.huobi.pro为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全
Не все биржи поддерживают FMZ, но платформа предоставляет доступ к общим соглашениям.
Проще говоря, общий протокол является посредником, который выполняет запросы хостера и возвращает данные в соответствии с соответствующими стандартами. Код общего протокола должен быть выполнен самостоятельно, а написание общего протокола фактически означает, что вы можете получить отдельный доступ к бирже, чтобы выполнить стратегию.
В частности, он отмечает, что “все это является результатом усилий, направленных на то, чтобы создать условия, которые позволили бы людям жить в мире, в котором они живут, и в котором они будут жить”. Пример написания общего протокола Python: https://www.fmz.com/strategy/101399
Как и в случае с биржами, все операции могут быть реализованы через API, веб-сайт FMZ также основан на API. Вы можете подать заявку на реализацию API-KEY своего веб-сайта FMZ, например, создать, перезапустить, удалить диск, получить список дисков, получить журнал дисков.
Благодаря мощной расширяемости платформы FMZ, вы можете создать свою собственную квантовую платформу на основе расширенного API, чтобы пользователи работали на вашей платформе.
Рынок торговли цифровыми валютами становится все более и более привлекательным для трейдеров-квантификаторов из-за его специфики. Фактически, программированные сделки уже являются основным направлением цифровых валют, а такие стратегии, как хеджирование и рынок, всегда активны на рынке. А новички с слабой программированием, которые хотят войти в эту область, сталкиваются с многочисленными биржами и многообразными API, с перевесом трудностей.
РаспространениеКурс количественной торговли цифровой валютой в сети NetEase Cloud❚ Зарегистрируйтесь в NetEase Cloud Classroom, поделитесь ссылкой на свой курс (ссылка содержит уникальный курс-ид), другие люди зарегистрируются по этой ссылке и покупают курс, и вы получите 50% от общего количества 10 юаней.
Потребитель нажимает на рекламную ссылку, и в течение полугода зарегистрировался на пополнение, наша компания возвращает комиссию в соответствии с действительной суммой в действительном заказе. Комиссия будет возвращена в виде доли на счет продвигателя, пользователь может обменять баланс счета на торговой платформе в соотношении 10:1, а также может впоследствии использовать доли для обмена на окружающие товары. Конкретная ссылка на мероприятие: https://www.fmz.com/bbs-topic/3828
FMZ веб-сайт может быть развернут на корпоративном или командном сервере, чтобы обеспечить полный контроль и функциональную настройку. FMZ веб-сайт используется и тестируется около 100 000 пользователей, достигает высокой доступности и безопасности, экономит время команды и предприятия.
Профессиональная система для обеспечения ликвидности рынка и управления капиталом для бирж, возможно, является самой совершенной системой торговли на рынке, используемой многими биржами и командами.
Технологическая торговая система изобретателя использует технологию слияния памяти, скорость обработки заказов до 2 миллионов рублей в секунду, которая гарантирует, что обработка заказов не будет задерживаться и загружаться. Она может поддерживать плавную и стабильную работу биржи с более чем 20 миллионами пользователей онлайн одновременно. Многоуровневая, многокластерная архитектура системы гарантирует безопасность, стабильность и легкость расширения системы. Развертывание функций и обновление версий без остановок обеспечивает максимальную безопасность пользовательского опыта для конечных пользователей. В настоящее время эта система доступна на аналогичной бирже wex.app.