[TOC]

Como plataforma de comercio cuantitativo, FMZ está diseñada principalmente para servir a los comerciantes programáticos. Pero también ofrece una terminal de operaciones básica. Aunque la función es sencilla, puede resultar muy útil en ocasiones. Por ejemplo, si el mercado está ocupado y no se puede abrir, pero la API aún puede funcionar, puede utilizar la terminal para cancelar órdenes. , realizar pedidos, ver cuentas de cotización, etc. Para mejorar la experiencia del terminal comercial, se ha agregado la funcionalidad de complemento. A veces, necesitamos una pequeña función que nos ayude en la negociación, como órdenes pendientes en escalera, órdenes iceberg, cobertura con un clic, cierre con un clic, etc. En realidad, no necesitamos mirar el registro de ejecución. Es un poco engorroso. Para crear un nuevo robot, solo tienes que hacer clic en el complemento en la terminal. Podrás realizar de inmediato las funciones correspondientes, lo que puede facilitar enormemente el comercio manual. La ubicación del complemento es la siguiente:

Hay dos modos de funcionamiento del complemento: funcionamiento inmediato y funcionamiento en segundo plano. Ejecutar en segundo plano equivale a crear un robot (se aplican los cargos normales). El principio de funcionamiento inmediato es el mismo que el de la herramienta de depuración: enviar un fragmento de código al custodio de la página del terminal comercial para su ejecución y admitir la devolución de gráficos y tablas (la herramienta de depuración también se ha actualizado actualmente para admitir esto). ). De igual forma, solo se puede ejecutar durante 5 minutos, de forma gratuita y con idioma ilimitado. Los complementos con tiempos de ejecución muy cortos pueden utilizar el modo de ejecución inmediata, mientras que las estrategias complejas que requieren mucho tiempo para ejecutarse aún requieren robots en ejecución.
Al escribir una política, debe seleccionar el tipo de política como complemento. El resultado de la función principal del complemento aparecerá en la terminal después de la ejecución, admitiendo cadenas, dibujos y tablas. Como los registros no se pueden ver durante la ejecución del complemento, se puede devolver el resultado de la ejecución del complemento.
Busque directamente en el cuadro de búsqueda como se muestra en la imagen.Tenga en cuenta que solo se pueden ejecutar estrategias de tipo complemento comercialy luego haga clic en Agregar. Los complementos públicos se pueden encontrar en Strategy Square: https://www.fmz.com/square/21/1

Haga clic en la estrategia para ingresar a la interfaz de configuración de parámetros. Si no hay parámetros, se ejecutará directamente. El custodio, el par comercial y el período de la línea K seleccionados por la terminal comercial son los parámetros correspondientes predeterminados. Haga clic en la política de ejecución para iniciar la ejecución y seleccione el modo “Ejecutar ahora” (puede recordar el modo de ejecución predeterminado). El complemento no mostrará registros.

Haga clic en el icono para detener el complemento. Dado que todos los complementos se ejecutan en un proceso de la herramienta de depuración, se detendrán todos.

Los complementos pueden ejecutar código durante un período de tiempo y realizar algunas operaciones simples. Muchas veces, las operaciones que deben repetirse manualmente se pueden implementar mediante complementos, lo que hace que las transacciones sean más convenientes. A continuación se presentará con ejemplos específicos y el código fuente proporcionado se puede utilizar como referencia para personalizar su propia estrategia.
La cobertura de futuros entre períodos es una estrategia muy común. Dado que la frecuencia no es muy alta, muchas personas la utilizan manualmente, lo que requiere que un contrato opere en largo y otro en corto, y pueden analizar la tendencia de la diferencia de precios. El uso de complementos en su terminal comercial le permitirá ahorrar energía.
Lo primero que quiero presentar es el complemento de diferencia de precios entre períodos:
var chart = {
__isStock: true,
title : { text : '差价分析图'},
xAxis: { type: 'datetime'},
yAxis : {
title: {text: '差价'},
opposite: false,
},
series : [
{name : "diff", data : []},
]
}
function main() {
exchange.SetContractType('quarter')
var recordsA = exchange.GetRecords(PERIOD_M5) //周期可以自行定制
exchange.SetContractType('this_week')
var recordsB = exchange.GetRecords(PERIOD_M5)
for(var i=0;i<Math.min(recordsA.length,recordsB.length);i++){
var diff = recordsA[recordsA.length-Math.min(recordsA.length,recordsB.length)+i].Close - recordsB[recordsB.length-Math.min(recordsA.length,recordsB.length)+i].Close
chart.series[0].data.push([recordsA[recordsA.length-Math.min(recordsA.length,recordsB.length)+i].Time, diff])
}
return chart
}
Con un solo clic, puede ver los diferenciales entre períodos recientes de un vistazo. Dirección de copia del código fuente del complemento: https://www.fmz.com/strategy/187755

Con el análisis de diferenciales, descubre que el diferencial está convergiendo, lo que representa una oportunidad para vender en corto el contrato trimestral y en largo la semana actual. En este momento, puede utilizar el complemento de cobertura con un solo clic. Con un solo clic, Te ayuda automáticamente a vender en corto el contrato trimestral y en largo el de la semana actual, lo que es más rápido que la operación manual. Bastantes. El principio de implementación de la estrategia es abrir la misma cantidad de posiciones con deslizamiento. Puedes ejecutarla varias veces para alcanzar lentamente la posición requerida y evitar impactar el mercado. Puedes cambiar los parámetros predeterminados para colocar órdenes más rápido. Dirección de copia de estrategia: https://www.fmz.com/strategy/191348
function main(){
exchange.SetContractType(Reverse ? Contract_B : Contract_A)
var ticker_A = exchange.GetTicker()
if(!ticker_A){return 'Unable to get quotes'}
exchange.SetDirection('buy')
var id_A = exchange.Buy(ticker_A.Sell+Slip, Amount)
exchange.SetContractType(Reverse ? Contract_B : Contract_A)
var ticker_B = exchange.GetTicker()
if(!ticker_B){return 'Unable to get quotes'}
exchange.SetDirection('sell')
var id_B = exchange.Sell(ticker_B.Buy-Slip, Amount)
if(id_A){
exchange.SetContractType(Reverse ? Contract_B : Contract_A)
exchange.CancelOrder(id_A)
}
if(id_B){
exchange.SetContractType(Reverse ? Contract_B : Contract_A)
exchange.CancelOrder(id_B)
}
return 'Position: ' + JSON.stringify(exchange.GetPosition())
}
Mientras espera que la diferencia de precio converja, si necesita cerrar la posición, puede ejecutar el complemento de cierre con un clic para cerrar la posición a la velocidad más rápida.
function main(){
while(ture){
var pos = exchange.GetPosition()
var ticker = exchange.GetTicekr()
if(!ticker){return '无法获取ticker'}
if(!pos || pos.length == 0 ){return '已无持仓'}
for(var i=0;i<pos.length;i++){
if(pos[i].Type == PD_LONG){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closebuy')
exchange.Sell(ticker.Buy, pos[i].Amount - pos[i].FrozenAmount)
}
if(pos[i].Type == PD_SHORT){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closesell')
exchange.Buy(ticker.Sell, pos[i].Amount - pos[i].FrozenAmount)
}
}
var orders = exchange.Getorders()
Sleep(500)
for(var j=0;j<orders.length;j++){
if(orders[i].Status == ORDER_STATE_PENDING){
exchange.CancelOrder(orders[i].Id)
}
}
}
}
La más común es la orden iceberg, que divide los pedidos grandes en pedidos más pequeños. Aunque se puede ejecutar como un robot, en realidad basta con un complemento de 5 minutos. Existen dos tipos de órdenes iceberg: una es para tomar la orden y la otra es para colocar la orden. Si hay un descuento en la tarifa de manejo, puede optar por colocar la orden, lo que significa que el tiempo de ejecución será más largo.
El siguiente código es el código fuente del complemento de compra de órdenes Iceberg: https://www.fmz.com/strategy/191771. Vender código fuente: https://www.fmz.com/strategy/191772
function main(){
var initAccount = _C(exchange.GetAccount)
while(true){
var account = _C(exchange.GetAccount)
var dealAmount = account.Stocks - initAccount.Stocks
var ticker = _C(exchange.GetTicker)
if(BUYAMOUNT - dealAmount >= BUYSIZE){
var id = exchange.Buy(ticker.Sell, BUYSIZE)
Sleep(INTERVAL*1000)
if(id){
exchange.CancelOrder(id) // May cause error log when the order is completed, which is all right.
}else{
throw 'buy error'
}
}else{
account = _C(exchange.GetAccount)
var avgCost = (initAccount.Balance - account.Balance)/(account.Stocks - initAccount.Stocks)
return 'Iceberg order to buy is done, avg cost is '+avgCost
}
}
}
Ocupar siempre el precio de comprar uno o vender uno es también una forma de enviar mercancías lentamente, lo que tiene un impacto relativamente pequeño en el mercado. Aún quedan algunas áreas por mejorar en esta estrategia. Puedes cambiar manualmente el volumen mínimo de transacciones o la precisión. Comprar: https://www.fmz.com/strategy/191582 Vender: https://www.fmz.com/strategy/191730
function GetPrecision(){
var precision = {price:0, amount:0}
var depth = exchange.GetDepth()
for(var i=0;i<exchange.GetDepth().Asks.length;i++){
var amountPrecision = exchange.GetDepth().Asks[i].Amount.toString().indexOf('.') > -1 ? exchange.GetDepth().Asks[i].Amount.toString().split('.')[1].length : 0
precision.amount = Math.max(precision.amount,amountPrecision)
var pricePrecision = exchange.GetDepth().Asks[i].Price.toString().indexOf('.') > -1 ? exchange.GetDepth().Asks[i].Price.toString().split('.')[1].length : 0
precision.price = Math.max(precision.price,pricePrecision)
}
return precision
}
function main(){
var initAccount = exchange.GetAccount()
if(!initAccount){return '无法获取账户信息'}
var precision = GetPrecision()
var buyPrice = 0
var lastId = 0
var done = false
while(true){
var account = _C(exchange.GetAccount)
var dealAmount = account.Stocks - initAccount.Stocks
var ticker = _C(exchange.GetTicker)
if(BuyAmount - dealAmount > 1/Math.pow(10,precision.amount) && ticker.Buy > buyPrice){
if(lastId){exchange.CancelOrder(lastId)}
var id = exchange.Buy(ticker.Buy, _N(BuyAmount - dealAmount,precision.amount))
if(id){
lastId = id
}else{
done = true
}
}
if(BuyAmount - dealAmount <= 1/Math.pow(10,precision.amount)){done = true}
if(done){
var avgCost = (initAccount.Balance - account.Balance)/dealAmount
return 'order is done, avg cost is ' + avgCost // including fee cost
}
Sleep(Intervel*1000)
}
}
A veces, para vender a un mejor precio o esperar una ganga, puedes realizar varios pedidos en un intervalo determinado. Este complemento también se puede utilizar para órdenes pendientes de futuros. Dirección de copia del código fuente: https://www.fmz.com/strategy/190017
function main() {
var ticker = exchange.GetTicker()
if(!ticker){
return 'Unable to get price'
}
for(var i=0;i<N;i++){
if(Type == 0){
if(exchange.GetName().startsWith('Futures')){
exchange.SetDirection('buy')
}
exchange.Buy(Start_Price-i*Spread,Amount+i*Amount_Step)
}else if(Type == 1){
if(exchange.GetName().startsWith('Futures')){
exchange.SetDirection('sell')
}
exchange.Sell(Start_Price+i*Spread,Amount+i*Amount_Step)
}else if(Type == 2){
exchange.SetDirection('closesell')
exchange.Buy(Start_Price-i*Spread,Amount+i*Amount_Step)
}
else if(Type == 3){
exchange.SetDirection('closebuy')
exchange.Sell(Start_Price+i*Spread,Amount+i*Amount_Step)
}
Sleep(500)
}
return 'order complete'
}
El software de negociación de futuros de uso común a menudo tiene muchas funciones avanzadas de colocación de órdenes, como colocar órdenes de stop-loss, colocar órdenes condicionales, etc., que se pueden escribir fácilmente en complementos. Aquí hay un complemento que le permite cerrar una orden pendiente inmediatamente después de su ejecución. Copiar dirección: https://www.fmz.com/strategy/187736
var buy = false
var trade_amount = 0
function main(){
while(true){
if(exchange.IO("status")){
exchange.SetContractType(Contract)
if(!buy){
buy = true
if(Direction == 0){
exchange.SetDirection('buy')
exchange.Buy(Open_Price, Amount)
}else{
exchange.SetDirection('sell')
exchange.Sell(Open_Price, Amount)
}
}
var pos = exchange.GetPosition()
if(pos && pos.length > 0){
for(var i=0;i<pos.length;i++){
if(pos[i].ContractType == Contract && pos[i].Type == Direction && pos[i].Amount-pos[i].FrozenAmount>0){
var cover_amount = math.min(Amount-trade_amount, pos[i].Amount-pos[i].FrozenAmount)
if(cover_amount >= 1){
trade_amount += cover_amount
if(Direction == 0){
exchange.SetDirection('closebuy_today')
exchange.Sell(Close_Price, cover_amount)
}else{
exchange.SetDirection('closesell_today')
exchange.Buy(Close_Price, cover_amount)
}
}
}
}
}
} else {
LogStatus(_D(), "未连接CTP !")
Sleep(10000)
}
if(trade_amount >= Amount){
Log('任务完成')
return
}
Sleep(1000)
}
}
Después de ver tantas funciones pequeñas, deberías tener tus propias ideas. También podrías escribirlas en complementos para facilitar tu operación manual.