В первоначальном дизайне политики FMZ использование асинхронных параллельных операций было разрешено только в том случае, если это необходимо.exchange.Go()
Функции, реализуемые для совмещения FMZ-встроенных интерфейсов, не могут одновременно выполнять некоторые пользовательские операции (функции). Хотя такая конструкция позволяет эффективно выполнять стратегические программы, но для одноклассников, которые имеют опыт совместного проектирования в родных языках, это очень непривычно.
Даже новые ученики, которые используют FMZ для ввода количественных сделок, не понимают.exchange.Go()
Использование функцийexchange.Go()
По-видимому, это все еще последовательное выполнение одного из них. В этой статье мы рассмотрим новые возможности совместных потоков на платформе FMZ:__Thread()
Использование серийных функций и т.д. не синхронизировано с разработкой стратегии.
Если мы хотим, чтобы главный строк стратегии работал одновременно с выполнением одной из подстрок для выполнения настройки, которую мы написали, мы можем использовать дизайн, похожий на следующий код.GetTickerAsync()
, чтобы написать конкретную функцию этой функции. Эта функция выполняет мертвый цикл, в которомwhile
API-интерфейс FMZ, постоянно вызывающий в цикле:GetTicker()
Посмотрите, что происходит в этом районе.
А затем использовать.__threadSetData(0, "ticker", t)
Эта фраза записывается в основную строку с данными, называемымиticker
, значение данногоt
То естьGetTicker()
В результате, мы получаем обратное значение.
__threadSetData(0, "ticker", t)
После того, как мы разработаем настраиваемые функции, которые выполняются одновременно, мы можем написатьmain()
И мы можем сделать это, если мы используем код в функции.main()
Для начала мы используем:
__Thread(GetTickerAsync, 0) // GetTickerAsync为需要并发执行的自定义函数,0为这个传入GetTickerAsync函数的参数
Мы создаем параллельную нить, которая начинает выполнятьGetTickerAsync()
Функция. Далее.main()
Функция начинает выполнять свою работу.while
Цикл, получающий в циклеGetTickerAsync()
Функция обновляет данные и печатает:
var t = __threadGetData(0, "ticker")
Log(t)
Полный пример кода:
function GetTickerAsync(index) {
while (true) {
var t = exchanges[index].GetTicker()
__threadSetData(0, "ticker", t)
Sleep(500)
}
}
function main() {
__Thread(GetTickerAsync, 0)
while(true) {
var t = __threadGetData(0, "ticker")
Log(t)
Sleep(1000)
}
}
Проверка на диске:
Это один из самых простых вариантов дизайна приложений, а теперь давайте посмотрим на другие варианты дизайна для нужд.
Можно спроектировать одну функцию, чтобы создать 10 потоков одновременно, каждый из которых выполняет одну подчиненную операционную функцию.main()
И мы можем сделать это.while
В этом случае, если вы хотите, чтобы ваш сайт был доступен для пользователей, вы можете использовать его для поиска информации о ваших пользователях.placeMultipleOrders
И мы должны сделать это, чтобы вызвать эту функцию.testPlaceMultipleOrders()
。
if (cmd == "placeMultipleOrders") {
// ...
}
Добавить интерактивный дизайн политики на странице редактирования политики, установить кнопку и команду: placeMultipleOrders
Полный пример кода:
function placeOrder(exIndex, type, price, amount) {
var id = null
if (type == "Buy") {
id = exchanges[exIndex].Buy(price, amount)
} else if (type == "Sell") {
id = exchanges[exIndex].Sell(price, amount)
} else {
throw "type error! type:" + type
}
}
function testPlaceMultipleOrders(index, beginPrice, endPrice, step, type, amount) {
Log("beginPrice:", beginPrice, ", endPrice:", endPrice, ", step:", step, ", type:", type, ", amount:", amount)
var tids = []
for (var p = beginPrice; p <= endPrice; p += step) {
var tid = __Thread(placeOrder, index, type, p, amount)
tids.push(tid)
Sleep(10)
}
Sleep(1000)
for (var i = 0; i < tids.length; i++) {
__threadTerminate(tids[i])
}
}
function main() {
while(true) {
LogStatus(_D())
var cmd = GetCommand()
if (cmd) {
if (cmd == "placeMultipleOrders") {
var t = _C(exchange.GetTicker)
var beginPrice = t.Last * 0.8
var endPrice = t.Last * 0.9
var step = t.Last * 0.01
testPlaceMultipleOrders(0, beginPrice, endPrice, step, "Buy", 0.01)
var orders = exchange.GetOrders()
for (var i = 0; i < orders.length; i++) {
Log(orders[i])
}
}
}
Sleep(1000)
}
}
Тестирование с использованием подвешенного списка, с наращиванием от 80% до 90% от текущей цены, с использованием дискового средного тестирования, нажатие интерактивной кнопки запускает тестовый список:
После нажатия кнопки "PlaceMultipleOrders" вы получаете сообщение:
В журнале стратегии отображаются следующие действия:
Это требование было предъявлено пользователем FMZ, который хотел бы иметь простой пример демонстрации использования в параллельных потоках.Веб-сокетМы создали систему, которая позволяет нам подключаться и проектировать, как передавать данные на основные провода.main()
Функция.
На самом деле это очень просто, и создание параллельных строк в этом примере почти то же самое, что и в предыдущем.__threadPeekMessage()
Функции и__threadPostMessage()
Функция. В качестве примера вызова интерфейса WebSocket API на бирже Bitcoin мы также должны обратить внимание на действие закрытия соединения WebSocket в дизайне. В следующем примере также показано, как дать уведомление о том, что одновременная нить должна быть остановлена.
Полный пример кода:
var tid = null
function createWS() {
// wss://stream.binance.com:9443/ws/<streamName> , <symbol>@ticker
var stream = "wss://stream.binance.com:9443/ws/btcusdt@ticker"
var ws = Dial(stream)
Log("创建WS连接:", stream)
while (true) {
var data = ws.read()
if (data) {
__threadPostMessage(0, data)
}
Log("接收到WS链接推送的数据,data:", data)
// __threadPeekMessage 超时参数设置-1,不阻塞
var msg = __threadPeekMessage(-1)
if (msg) {
if (msg == "stop") {
Log("并发线程Id:", __threadId(), "接收到stop指令")
break
}
}
}
Log("并发线程执行完毕,关闭ws连接")
ws.close()
}
function main() {
tid = __Thread(createWS)
Log("创建并发线程,线程Id:", tid)
while(true) {
// __threadPeekMessage 的超时参数设置为0,阻塞等待数据
var data = __threadPeekMessage(0)
Log("接收到并发线程", ", Id:", tid, ", 发送的数据,data:", data, "#FF0000")
var tbl = {
type : "table",
title : "<symbol>@ticker频道推送消息",
cols : ["事件类型", "事件时间", "交易对", "24小时价格变化", "24小时价格变化百分比", "平均价格", "最新成交价格", "24小时内成交量", "24小时内成交额"],
rows : []
}
try {
data = JSON.parse(data)
tbl.rows.push([data.e, _D(data.E), data.s, data.p, data.P, data.w, data.c, data.v, data.q])
} catch (e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
}
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
}
}
function onexit() {
Log("扫尾函数,向Id为", tid, "的并发线程发送stop指令")
__threadPostMessage(tid, "stop")
Log("等待Id为", tid, "的并发线程停止")
__threadJoin(tid)
Log("扫尾函数执行完毕")
}
Проверка на диске:
Вы можете видетьmain()
Функция непрерывно получает трафикные данные, полученные от соединения WebSocket, созданного одновременно с проводами.
При остановке реального диска политика запускает функцию стереотипа:
Спарта играет в количественном режимеИ последний пример, если у вас много ws-потоков, и вы подписаны на несколько тем, то что лучше для общения между потоками, как получить/установить или посмотреть/положить?
Спарта играет в количественном режимеВ основном реализация межуровневых общих переменных не поддерживает ссылки на переменные, которые необходимо перезагружать с каждым обновлением, что неэффективно.
Изобретатели количественного измерения - мечтыПоскольку они не имеют никакой разницы, они могут быть любыми способами.