
Cuando estaba hablando de estrategias con mis amigos recientemente, aprendí que muchas personas que usan mi lenguaje para escribir estrategias sufren el problema de la flexibilidad. En muchos casos es necesario utilizar un período K-line estándar que no proporciona el sistema. Por ejemplo, el requisito más solicitado es utilizar un período K-line de 4 horas. Este problema se ha solucionado en un artículo. Si te interesa, puedes echarle un vistazo primero:Enlace. Sin embargo, en la estrategia de mi lenguaje, debido a la naturaleza altamente encapsulada de mi lenguaje, este problema no puede procesar datos de manera flexible por sí solo. En estos momentos es necesario trasplantar el pensamiento estratégico a otros lenguajes.
Es muy sencillo trasplantar estrategias de tendencia. Podemos utilizar un código de muestra para completar la parte de cálculo de datos de la estrategia impulsora y completar las condiciones de activación de la señal comercial.
Tomemos como ejemplo la estrategia utilizada para los futuros de OKEX.
// 全局变量
var IDLE = 0
var LONG = 1
var SHORT = 2
var OPENLONG = 3
var OPENSHORT = 4
var COVERLONG = 5
var COVERSHORT = 6
var BREAK = 9
var SHOCK = 10
var _State = IDLE
var Amount = 0 // 记录持仓数量
var TradeInterval = 500 // 轮询间隔
var PriceTick = 1 // 价格一跳
var Symbol = "this_week"
function OnTick(){
// 驱动策略的行情处理部分
// 待填充...
// 交易信号触发处理部分
// 待填充...
// 执行交易逻辑
var pos = null
var price = null
var currBar = records[records.length - 1]
if(_State == OPENLONG){
pos = GetPosition(PD_LONG)
// 判断是不是 满足状态,如果满足 修改状态
if(pos[1] >= Amount){
_State = LONG
Amount = pos[1] // 更新实际量
return
}
price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
Trade(OPENLONG, price, Amount - pos[1], pos, PriceTick) // (Type, Price, Amount, CurrPos, PriceTick)
}
if(_State == OPENSHORT){
pos = GetPosition(PD_SHORT)
if(pos[1] >= Amount){
_State = SHORT
Amount = pos[1] // 更新实际量
return
}
price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)
}
if(_State == COVERLONG){
pos = GetPosition(PD_LONG)
if(pos[1] == 0){
_State = IDLE
return
}
price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
Trade(COVERLONG, price, pos[1], pos, PriceTick)
}
if(_State == COVERSHORT){
pos = GetPosition(PD_SHORT)
if(pos[1] == 0){
_State = IDLE
return
}
price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
Trade(COVERSHORT, price, pos[1], pos, PriceTick)
}
}
// 交易逻辑部分
function GetPosition(posType) {
var positions = _C(exchange.GetPosition)
var count = 0
for(var j = 0; j < positions.length; j++){
if(positions[j].ContractType == Symbol){
count++
}
}
if(count > 1){
throw "positions error:" + JSON.stringify(positions)
}
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType == Symbol && positions[i].Type === posType) {
return [positions[i].Price, positions[i].Amount];
}
}
Sleep(TradeInterval);
return [0, 0];
}
function CancelPendingOrders() {
while (true) {
var orders = _C(exchange.GetOrders)
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
Sleep(TradeInterval);
}
if (orders.length === 0) {
break;
}
}
}
function Trade(Type, Price, Amount, CurrPos, OnePriceTick){ // 处理交易
if(Type == OPENLONG || Type == OPENSHORT){ // 处理开仓
exchange.SetDirection(Type == OPENLONG ? "buy" : "sell")
var pfnOpen = Type == OPENLONG ? exchange.Buy : exchange.Sell
var idOpen = pfnOpen(Price, Amount, CurrPos, OnePriceTick, Type)
Sleep(TradeInterval)
if(idOpen) {
exchange.CancelOrder(idOpen)
} else {
CancelPendingOrders()
}
} else if(Type == COVERLONG || Type == COVERSHORT){ // 处理平仓
exchange.SetDirection(Type == COVERLONG ? "closebuy" : "closesell")
var pfnCover = Type == COVERLONG ? exchange.Sell : exchange.Buy
var idCover = pfnCover(Price, Amount, CurrPos, OnePriceTick, Type)
Sleep(TradeInterval)
if(idCover){
exchange.CancelOrder(idCover)
} else {
CancelPendingOrders()
}
} else {
throw "Type error:" + Type
}
}
function main() {
// 设置合约
exchange.SetContractType(Symbol)
while(1){
OnTick()
Sleep(1000)
}
}
Prueba retrospectiva del idioma Mai:

Código de estrategia del idioma Mai:
MA5^^MA(C,5);
MA15^^MA(C,15);
CROSSUP(MA5,MA15),BPK;
CROSSDOWN(MA5,MA15),SPK;
Primero, complete las partes de adquisición de mercado y cálculo de indicadores en el código de muestra reutilizable:
// 驱动策略的行情处理部分
var records = _C(exchange.GetRecords)
if (records.length < 15) {
return
}
var ma5 = TA.MA(records, 5)
var ma15 = TA.MA(records, 15)
var ma5_pre = ma5[ma5.length - 3]
var ma15_pre = ma15[ma15.length - 3]
var ma5_curr = ma5[ma5.length - 2]
var ma15_curr = ma15[ma15.length - 2]
Como puede ver, la estrategia de media móvil doble es muy sencilla. Solo es necesario obtener primero los datos de la línea K.records, luego usaTA函数库Función de media móvilTA.MACalcule el promedio móvil de 5 días y el promedio móvil de 15 días (puede ver en la interfaz de backtest que el período de la línea K está configurado en la línea K diaria, por lo queTA.MA(records, 5)Se calcula el promedio móvil de 5 días.TA.MA(records, 15)Promedio móvil de 15 días).
Entonces consiguema5El segundo al último punto de los datos del indicadorma5_curr(Valor del indicador), antepenúltimo puntoma5_pre(Valor del indicador),ma15Lo mismo se aplica a los datos de los indicadores. Luego, puede utilizar estos datos indicadores para juzgar la cruz dorada y la cruz muerta, como se muestra en la figura:
Mientras se forme tal estado, será una cruz dorada confirmada o una cruz muerta.
Entonces la parte de juicio de señal se puede escribir como:
if(_State == IDLE && ma5_pre < ma15_pre && ma5_curr > ma15_curr){
_State = OPENLONG
Amount = 1
}
if(_State == IDLE && ma5_pre > ma15_pre && ma5_curr < ma15_curr){
_State = OPENSHORT
Amount = 1
}
if(_State == LONG && ma5_pre > ma15_pre && ma5_curr < ma15_curr){
_State = COVERLONG
Amount = 1
}
if(_State == SHORT && ma5_pre < ma15_pre && ma5_curr > ma15_curr){
_State = COVERSHORT
Amount = 1
}
Esto significa que el trasplante está bien y puedes volver y analizarlo:
Estrategias de backtesting de JavaScript
Configuración de backtest:

回测结果:

Prueba retrospectiva de mi lenguaje

Se puede ver que los resultados de las pruebas retrospectivas son básicamente los mismos, por lo que si desea continuar agregando funciones interactivas a la estrategia, agregar procesamiento de datos (como la síntesis de línea K) y agregar visualización y dibujo de gráficos personalizados, puede hacerlo. él.
Los estudiantes que estén interesados pueden intentarlo.