En el diseño original de la política FMZ, sólo se podía usar una operación asíncrona si se necesitaba.exchange.Go()
Las funciones para implementar la concurrencia de la interfaz de envase FMZ no pueden ejecutar simultáneamente algunas operaciones personalizadas (funciones). Aunque este diseño mejora mucho la eficiencia de la ejecución de los programas estratégicos, los estudiantes con experiencia en diseño simultáneo en los lenguajes nativos no están acostumbrados a la sensación general.
Incluso los nuevos estudiantes que usan FMZ para introducir transacciones cuantitativas no lo entienden.exchange.Go()
Uso de funciones, usoexchange.Go()
En este artículo, vamos a explorar las nuevas funciones de los hilos de concurrencia de la plataforma FMZ:__Thread()
El uso de la serie de funciones, etc., es asíncrono con el diseño del procedimiento de la política.
Si queremos que el hilo principal de la política se ejecute al mismo tiempo que se ejecuta un subdirectorio para ejecutar la función personalizada que hemos escrito, podemos usar un diseño similar al siguiente código.GetTickerAsync()
Esta función ejecuta un ciclo muerto, en el que el valor de la función es el valor de la función.while
La interfaz API de FMZ que llama continuamente en el circuito:GetTicker()
En la actualidad, la mayoría de los usuarios de Twitter están en línea con sus redes sociales.
Y luego usarlo.__threadSetData(0, "ticker", t)
Esta frase escribe un dato en el hilo principal, llamado nombre de datos.ticker
El valor de los datos est
Es decir,GetTicker()
El valor de retorno de los números de las partidas es:
__threadSetData(0, "ticker", t)
Y después de diseñar las funciones personalizadas que se ejecutan a la vez, podemos escribirmain()
La función está en el código.main()
La función comienza con:
__Thread(GetTickerAsync, 0) // GetTickerAsync为需要并发执行的自定义函数,0为这个传入GetTickerAsync函数的参数
Creamos un hilo paralelo que comienza a ejecutarse.GetTickerAsync()
Función. Luegomain()
Las funciones comienzan a ejecutarse.while
Circulan, reciben en el cicloGetTickerAsync()
La función actualiza los datos y luego imprime:
var t = __threadGetData(0, "ticker")
Log(t)
Un ejemplo de código completo:
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)
}
}
La prueba en disco real:
Este es el diseño de aplicaciones más sencillo, ahora vamos a ver otros diseños de necesidades.
Se puede diseñar una función para crear 10 hilos simultáneamente, cada uno de los cuales ejecuta una función operativa de orden inferior.main()
Diseñar una funciónwhile
En la página web del sitio web, el usuario puede encontrar instrucciones de interacción de la política de detección.placeMultipleOrders
Así que esto es lo que llamamos.testPlaceMultipleOrders()
。
if (cmd == "placeMultipleOrders") {
// ...
}
Añadir diseño interactivo de la política en la página de edición de la política, establecer un botón con el comando: placeMultipleOrders
Un ejemplo de código completo:
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)
}
}
Prueba de la manera de usar el menú colgado, incrementado desde el 80% hasta el 90% del precio actual, prueba del entorno del disco analógico, clicando en el botón interactivo para activar el menú de prueba:
Después de hacer clic en el botón "placeMultipleOrders", se muestra el siguiente mensaje:
En el registro de estrategias se muestra la siguiente operación simultánea:
Este requisito fue presentado por un usuario de FMZ, con la esperanza de tener un ejemplo simple que demuestre cómo usarlo en hilos paralelos.WebSocket y el sistema operativoLa conexión y diseño de cómo transmitir los datos a los hilos principalesmain()
La función.
En realidad, es muy sencillo, y es casi lo mismo que crear hilos simultáneos en el ejemplo anterior; pero se utiliza para la comunicación entre hilos.__threadPeekMessage()
Función y__threadPostMessage()
Función. Tomando como ejemplo la llamada a la API de WebSocket de Bitcoin Exchange, en el diseño también necesitamos prestar atención a la operación de cierre de la conexión WebSocket, y el siguiente ejemplo también muestra cómo notificar a un hilo simultáneo para que se detenga.
Un ejemplo de código completo:
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("扫尾函数执行完毕")
}
La prueba en disco real:
Se puede vermain()
La función recibe continuamente datos de mercado de las conexiones WebSocket creadas en la misma cadena.
Cuando se detiene la política en vivo, la función de barrido comienza a funcionar:
Esparta jugando a la cantidadUn último ejemplo, si hay muchos hilos ws y se suscribe a varios temas, ¿cuál es el mejor rendimiento para la comunicación entre hilos, usar el método get / set o el método peek / post?
Esparta jugando a la cantidadLa implementación básica de variables compartidas entre hilos es que no soporta variables de referencia, y tiene que ser reestablecida cada vez que se actualiza, lo cual es muy bajo en eficiencia.
Los inventores cuantifican - sueños pequeñosLas dos formas no son muy diferentes, pueden ser.