Recientemente, las estrategias de tipo Martin se han discutido mucho en el grupo oficial de FMZ, y no hay muchas estrategias de tipo Martin en la plataforma sobre contratos de moneda digital. Por lo tanto, aproveché la oportunidad para diseñar una estrategia simple de tipo Martin para futuros de moneda digital.
Este artículo trata sobre todo de aprender desde el diseño de estrategias tipo Martin, las ideas estratégicas en sí mismas son muy claras, y como usuarios de FMZ, pensamos más en el diseño de estrategias.
Cuando se diseña una estrategia de futuros de moneda digital, a menudo se utiliza este dato como beneficio total. Porque se calcula el rendimiento, especialmente cuando se necesita calcular el rendimiento flotante.exchange.GetAccount()
Se obtienen los activos disponibles y los activos congelados en los registros. De hecho, la mayoría de los intercambios de futuros de moneda digital ofrecen este dato, pero FMZ no tiene un paquete uniforme de este atributo.
Así que obtuvimos estos datos de acuerdo con las diferentes funciones de diseño de los intercambios:
// OKEX V5 获取总权益
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
// 币安期货
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
En el códigototalEquity
Es el beneficio total que necesitamos. Luego escribimos una función como entrada de llamada para llamar a la función correspondiente según el nombre del intercambio.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
Antes de diseñar la función principal, la lógica principal. También necesitamos hacer algunos preparativos para diseñar algunas funciones auxiliares.
Cancelar todas las listas pendientes actuales
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
Sleep(500)
}
}
Esta función es muy familiar para aquellos que suelen leer el código de patrones de estrategia en la plaza de estrategias de FMZ, y muchas estrategias han usado un diseño similar.
Operaciones de compra de futuros
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
Las operaciones de futuros tienen cuatro direcciones: abierto largo, abierto corto, abierto largo y cubierto corto. Así que hemos diseñado cuatro funciones de pedido para corresponder a estas operaciones. Si solo se considera el pedido, hay varios factores necesarios: dirección, precio del pedido, cantidad del pedido.
Así que también hemos diseñado una llamada:trade
La función para tratar cuando方向(distance)
、下单价格(price)
、下单量(amount)
Los usuarios de Twitter también han sido informados de que los usuarios de Twitter han estado usando la aplicación para hacer sus propios comentarios.
Las llamadas a las funciones openLong, openShort, coverLong y coverShort se realizan en el final de la función.trade
La función cumple con su función real, es decir, realiza pedidos en el mercado de futuros según una dirección, precio o cantidad establecidos.
La estrategia es muy simple: pegar un pedido de compra o venta a cierta distancia por debajo de la línea de base en el precio actual. Una vez que se realiza la transacción, se cancelan todos los pedidos restantes, y luego se cuelgan nuevos pedidos de liquidación a cierta distancia según el precio del stock, y se cuelgan pedidos de aumento de stock en el precio actual después de la actualización, pero no se duplica el volumen del pedido.
Trabajo inicial Para que la lista se ponga, necesitamos dos variables globales para registrar el ID de la orden.
var buyOrderId = null
var sellOrderId = null
Luego se diseñó la opción de usar el disco OKEX_V5 en los parámetros de la interfaz de la política, por lo que hay que hacer algunas manipulaciones en el código:
var exName = exchange.GetName()
// 切换OKEX V5模拟盘
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
Los parámetros de la interfaz también diseñan la opción de restablecer toda la información, por lo que el código también tiene el procesamiento correspondiente:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
Nosotros sólo corremos un pacto perpetuo, así que aquí está escrito muerto, sólo se establece como un pacto perpetuo.
exchange.SetContractType("swap")
Luego tenemos que tener en cuenta el problema de la precisión del precio del pedido, la precisión del pedido, si la precisión no está bien configurada, la precisión se pierde durante el cálculo de la estrategia, y muchos dígitos de datos pueden causar que el intercambio rechace el pedido.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
Funciones de recuperación de datos de diseño sencillo
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "获取初始权益失败"
}
} else {
totalEq = recoverTotalEq
}
}
Si desea especificar el total de intereses de la cuenta inicial cuando se ejecute la política, puede establecer el parámetrototalEq
Si el parámetro está configurado en -1, la política leerá los datos de utilidad total almacenados. Si no se guardan los datos de utilidad total, se usará el total de utilidad total de la estrategia como el progreso inicial de la estrategia, y luego el aumento de la utilidad total indicará que no, y la disminución de la utilidad total indicará que no. Si se lee los datos de utilidad total, se continuará con el uso de estos datos.
La lógica principal Después de haber hecho el trabajo inicial, finalmente llego a la parte de la lógica principal de la estrategia, y para facilitar la explicación, escribí la explicación directamente en la nota del código.
while (1) { // 策略主要逻辑设计为一个死循环
var ticker = _C(exchange.GetTicker) // 首先读取当前行情信息,主要用到最新成交价
var pos = _C(exchange.GetPosition) // 读取当前持仓数据
if (pos.length > 1) { // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
Log(pos)
throw "同时有多空持仓" // 抛出错误,让策略停止
}
// 根据状态而定
if (pos.length == 0) { // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
// 未持仓了,统计一次收益
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // 挂开多仓的买单
sellOrderId = openShort(ticker.Last + targetProfit, amount) // 挂开空仓的卖单
} else if (pos[0].Type == PD_LONG) { // 有多头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = openLong(price - targetProfit * n, amount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) { // 有空头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, amount)
}
if (!sellOrderId || !buyOrderId) { // 如果有一边挂单失败就取消所有挂单,重来
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // 挂单完成,开始监控订单
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
}
}
if (!isFindSellId && !isFindBuyId) { // 检测到买卖单都成交了
cancelAll()
break
} else if (!isFindBuyId) { // 检测到买单成交
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) { // 检测到卖单成交
Log("卖单成交")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
La lógica y el diseño están listos.
El 19 de mayo fue un día de estrategias.
Como se puede ver, la estrategia del tipo Martín sigue teniendo cierto riesgo.
La dirección de la estrategia:https://www.fmz.com/strategy/294957
Las estrategias son principalmente para aprender, pero el oro y la plata de verdad se usan con cuidado ~!
- ¿Qué quieres decir?¿Qué es lo que quiere decir? if (!isFindSellId &&!isFindBuyId) { // detecta que todos los pedidos de compra y venta se han realizado ¿Se puede detectar un error si se realiza una compra y venta al mismo tiempo que se realiza una compra y venta con una conexión rápida?
Nuevo 1898¿Cómo se establece el modelo de contrato, todo o por acción?
Nuevo 1898¿Por qué no se establece el doble de contrato? ¿Cuántas veces se vende?
Nube ligeraGracias Dreama, por fin entiendo de principio a fin. Luego aprendí a colgar el monitor y escribí un Martin bilateral. Durante dos días, escribí 580 líneas. Gracias, muchachos.
cantidad de hk/upload/asset/1a9ebf427c4e2cbf1c327.png /upload/asset/1a9ebf427c4e2cbf1c327.png /upload/asset/1a9ebf427c4e2cbf1c327.png ¿Falso verdad en cambio?
Los sueños cuestan ocho cifras.¿Qué pasa si
Los sueños cuestan ocho cifras.Los intereses de los propietarios
No hay nada¿Necesitamos detener el daño?
¿ Qué pasa?Martin, vuelve a medir y es 0.
¿Qué es?¿No entiende que el número de números es igual a = y que n siempre es igual a 1?
- ¿ Qué pasa?¿La estrategia es doble abierta o abierta por separado?
Los inventores cuantifican - sueños pequeñosNo lanza errores. Todavía cancela todos los pedidos suspendidos, salta del ciclo actual y continúa con la lógica de los pedidos suspendidos.
Los inventores cuantifican - sueños pequeñosPor lo general, se usa todo el almacén.
Los inventores cuantifican - sueños pequeñosEl apalancamiento se puede establecer en el mercado de valores, según sus preferencias de riesgo.
Los inventores cuantifican - sueños pequeños¡El total de las nubes es 666!
Los inventores cuantifican - sueños pequeñosSi la variable se llama isFindBuyId, no es apropiado.
Los inventores cuantifican - sueños pequeñosEsta estrategia no está diseñada para detener los daños. Así que la curva que sale puede verse como una forma de subir.
Los inventores cuantifican - sueños pequeñosHa ha, el destino de Martin. Este artículo está diseñado principalmente para la estrategia de enseñanza, sin tener que prestar mucha atención a los beneficios.
Los inventores cuantifican - sueños pequeñosLa N se usa para hacer cambios posteriores, por ejemplo, pensar en n veces la distancia de acoplamiento, que se puede establecer temporalmente como 1⁄2.
Los inventores cuantifican - sueños pequeñosEn el video, la mujer dice: