[TOC]

Com o rápido desenvolvimento da tecnologia de inteligência artificial (IA), ela demonstrou eficiência e criatividade extremamente altas em muitos campos. Como um campo altamente técnico, a negociação quantitativa também está explorando ativamente a aplicação da IA. Entretanto, na prática, descobriremos que ainda há grandes desafios em confiar somente na IA para gerar diretamente estratégias de negociação completas, estáveis e sustentáveis e lucrativas.
Especialmente para novos usuários na plataforma, devido às suas fracas habilidades de programação, é difícil implementar suas ideias de negociação em códigos de estratégia. Embora atualmente possamos contar nossas ideias à IA e deixá-la gerar estratégias. Entretanto, o efeito da implementação não correspondeu às expectativas. Muitas vezes encontro usuários que vêm fazer perguntas com códigos gerados por IA e, às vezes, consigo ver as estratégias geradas por IA rapidamente. Como ainda há muitos problemas com os códigos de estratégia gerados pela IA neste estágio, usar a IA dessa maneira não só não resolve nenhum problema, mas também traz mais confusão e problemas para os novatos. Quanto mais eu aprendia, mais confuso eu ficava e, no final, “desisti de começar”.
Pessoalmente, acredito que há duas razões principais para os problemas atuais com as estratégias de produção direta da IA:
Então, existem outros métodos de aplicação mais eficientes? Este artigo gostaria de compartilhar uma nova maneira de pensar: deixar que a IA nos ajude a aprender estratégias existentes, entender o design da estratégia, extrair detalhes e técnicas importantes e analisar melhor sua eficácia e espaço para melhorias. Este método não só pode nos ajudar a compreender a essência do design de estratégia mais rapidamente, mas também melhorar sistematicamente nosso nível de negociação quantitativa.
Aproveitando a IA, ela pode ter uma compreensão relativamente precisa da análise de código específica, porque para a IA, os dados do código são “1 é 1, 2 é 2” e não haverá confusão lógica, ambiguidade ou outros problemas causados por requisitos de descrição de linguagem natural. Então, por que não usar as vantagens da IA para reduzir a carga de trabalho manual e aproveitar ao máximo as vantagens do trabalho manual?
Pode ser dividido nas seguintes etapas:
Selecione uma estratégia existente Pode ser escrito por você mesmo, de código aberto ou um excelente exemplo de estratégia na plataforma quantitativa do inventor.
Deixe a IA nos ajudar a explicar a estratégia
Entenda a ideia geral
Classifique os módulos funcionais de cada parte
Esclarecer os indicadores, parâmetros e lógica de negociação utilizados
Em que condições de mercado a estratégia tem melhor desempenho?
Quais são os possíveis pontos de risco?
Quais áreas podem ser otimizadas e melhoradas?
Backtesting em diferentes produtos e períodos
Adicionar filtros adicionais ou medidas de controle de risco
Observe as mudanças de desempenho e forme seus próprios insights
Vamos deixar que a IA aprenda uma estratégia e a explique para nós para ver se ela atende às nossas expectativas. Pode nos ajudar a aprender quantificação.
Projeto e implementação de uma estratégia de negociação de aumento de posição passo a passo com base na filtragem de tendência EMA Endereço estratégico: https://www.fmz.com/strategy/492116
/*backtest
start: 2024-10-01 00:00:00
end: 2025-04-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
args: [["targetProfit",20],["amount",20],["amountPrecision",3],["isAmountForUSDT",true]]
*/
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
}
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
function ceilToDecimals(value, decimals) {
const factor = Math.pow(10, decimals);
return Math.ceil(value * factor) / factor;
}
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(interval)
}
Sleep(interval)
}
}
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)
}
function plotRecords(c, buyOrder, sellOrder, pos) {
var bars = _C(exchange.GetRecords)
if (bars.length == 0) {
return
}
bars.forEach(function(bar, index) {
c.begin(bar)
if (index == bars.length - 1) {
if (buyOrder) {
c.hline(buyOrder.Price, "buy", "rgba(255, 0, 0, 0.2)", "dotted")
}
if (sellOrder) {
c.hline(sellOrder.Price, "sell", "rgba(0, 255, 0, 0.2)", "dotted")
}
if (pos && pos.length == 1) {
c.hline(pos[0].Price, "pos", "rgba(0, 0, 255, 0.2)", "dashed")
}
}
c.close()
})
}
var buyOrderId = null
var sellOrderId = null
var logStatusMsgBuff = ""
function main() {
var exName = exchange.GetName()
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
exchange.SetContractType(contractType)
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
exchange.SetMarginLevel(marginLevel)
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
}
}
var addCounter = _G("addCounter")
if (!addCounter) {
addCounter = 1
if (setAddCounter != -1) {
addCounter = setAddCounter
}
_G("addCounter", addCounter)
} else {
addCounter -= 1
}
let c = KLineChart({
overlay: true
})
var isLock = false
while (true) {
var ticker = _C(exchange.GetTicker)
var pos = _C(exchange.GetPosition)
if (pos.length > 1) {
Log(pos)
throw "同时有多空持仓"
}
var r = _C(exchange.GetRecords, 60 * 60)
var ema = TA.EMA(r, 60)
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] > 0.03) {
cancelAll()
isLock = true
}
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] < 0.02) {
isLock = false
}
if (isLock) {
LogStatus(_D(), "暂停, 检测阈值:", _N(Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2], 3), logStatusMsgBuff)
plotRecords(c, null, null, pos)
Sleep(interval)
continue
}
var currentAcc = _C(exchange.GetAccount)
if (currentAcc.Balance < totalEq * reserve) {
throw "no money, stop"
}
if (addCounter > maxAddCounter) {
LogStatus(_D(), "加仓已达到上限", logStatusMsgBuff)
if (isMaxAddCounterClear && pos.length >= 1) {
Log("加仓已达到上限,撤单,清仓")
cancelAll()
if (pos[0].Type == PD_LONG) {
var coverId = coverLong(-1, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) {
var coverId = coverShort(-1, pos[0].Amount)
}
addCounter = 1
}
continue
}
if (pos.length == 0) {
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
var tradeAmountLong = amount
var tradeAmountShort = amount
if (isAmountForUSDT) {
tradeAmountLong = ceilToDecimals(tradeAmountLong * 1.01 / (ticker.Last - targetProfit / 5) / oneCtValue, amountPrecision)
tradeAmountShort = ceilToDecimals(tradeAmountShort * 1.01 / (ticker.Last + targetProfit / 5) / oneCtValue, amountPrecision)
}
buyOrderId = openLong(ticker.Last - targetProfit / 5, tradeAmountLong)
sellOrderId = openShort(ticker.Last + targetProfit / 5, tradeAmountShort)
addCounter = 1
_G("addCounter", addCounter)
} else if (pos[0].Type == PD_LONG) {
var n = ratio
var price = ticker.Last
var addAmount = isDoubling ? pos[0].Amount : (isAmountForUSDT ? (ceilToDecimals(amount * 1.01 / (price - targetProfit * n) / oneCtValue, amountPrecision)) : amount)
buyOrderId = openLong(price - targetProfit * n, addAmount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
addCounter++
_G("addCounter", addCounter)
} else if (pos[0].Type == PD_SHORT) {
var n = ratio
var price = ticker.Last
var addAmount = isDoubling ? pos[0].Amount : (isAmountForUSDT ? (ceilToDecimals(amount * 1.01 / (price + targetProfit * n) / oneCtValue, amountPrecision)) : amount)
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, addAmount)
addCounter++
_G("addCounter", addCounter)
}
if (!sellOrderId || !buyOrderId) {
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) {
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
var buyOrder = null
var sellOrder = null
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
buyOrder = orders[i]
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
sellOrder = orders[i]
}
}
if (!isFindSellId && !isFindBuyId) {
cancelAll()
break
} else if (!isFindBuyId) {
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) {
Log("卖单成交")
cancelAll()
break
}
var acc = _C(exchange.GetAccount)
var tbl = {"type": "table", "title": "data", "cols": ["data", "symbol", "type", "price", "amount"], "rows": []}
if (buyOrder) {
tbl.rows.push(["订单", buyOrder.Symbol, buyOrder.Type == ORDER_TYPE_BUY ? "买入" : "卖出", buyOrder.Price, buyOrder.Amount])
}
if (sellOrder) {
tbl.rows.push(["订单", sellOrder.Symbol, sellOrder.Type == ORDER_TYPE_BUY ? "买入" : "卖出", sellOrder.Price, sellOrder.Amount])
}
if (pos && pos.length == 1) {
tbl.rows.push(["持仓", pos[0].Symbol, pos[0].Type == PD_LONG ? "多" : "空", pos[0].Price, pos[0].Amount])
}
logStatusMsgBuff = "当前权益:" + acc.Equity + ", 初始权益:" + totalEq + (!IsVirtual() ? ", 浮动盈亏:" + (acc.Equity - totalEq) : "") + ", 加仓次数:" + addCounter + "\n`" + JSON.stringify(tbl) + "`"
LogStatus(_D(), "当前权益:", acc.Equity, ", 初始权益:", totalEq, !IsVirtual() ? ", 浮动盈亏:" + (acc.Equity - totalEq) : "", ", 加仓次数:" + addCounter, "\n`" + JSON.stringify(tbl) + "`")
plotRecords(c, buyOrder, sellOrder, pos)
Sleep(interval)
}
Sleep(interval)
}
}
function onexit() {
Log("扫尾,撤销所有挂单")
cancelAll()
}
Para novos alunos da plataforma FMZ, ver uma pilha de códigos como essa pode fazer você se sentir perdido. Em vez de estudar o código linha por linha, podemos muito bem (ser preguiçosos) e entregá-lo à IA, deixar que ela nos explique e melhorar a eficiência do aprendizado.
Estou usando GPT aqui, e o conteúdo a seguir é explicado pela IA:
Uma visão geral Este artigo apresentará uma estratégia de negociação passo a passo para aumento de posição com base na filtragem de tendência EMA (média móvel exponencial). Esta estratégia é usada principalmente na Binance Futures (Futures_Binance), suporta backtesting de 1 hora e é baseada na agregação de dados de K-line de 1 minuto. Por meio do monitoramento em tempo real do desvio entre o preço e a EMA, a estratégia alterna dinamicamente os modos de negociação (negociação normal/negociação suspensa), aumenta gradualmente as posições em um mercado estável e suspende automaticamente as posições em flutuações anormais para evitar riscos.
flowchart TD
开始 --> 初始化参数
初始化参数 --> 账户余额检查
账户余额检查 --> 计算EMA
计算EMA --> 判断是否锁仓
判断是否锁仓 -->|是| 暂停交易
判断是否锁仓 -->|否| 正常交易
正常交易 --> 是否有持仓
是否有持仓 -->|无| 首次挂单
是否有持仓 -->|有| 按持仓方向加仓与止盈挂单
首次挂单 --> 等待成交
按持仓方向加仓与止盈挂单 --> 等待成交
等待成交 --> 挂单成交检测
挂单成交检测 --> 成交后调整
成交后调整 --> 更新加仓次数
更新加仓次数 --> 是否超出最大加仓次数
是否超出最大加仓次数 -->|是| 平仓
是否超出最大加仓次数 -->|否| 继续交易
Cinco, resumo Essa estratégia de aumento de posição passo a passo com base na filtragem de EMA leva em consideração tanto os retornos quanto o controle de risco e é adequada para operar em um mercado volátil e fracamente volátil. Por meio de métodos flexíveis de adição de posições e mecanismos de pausa de tendências, a probabilidade de liquidação pode ser efetivamente reduzida e a eficiência do uso de capital pode ser melhorada. Ele suporta tanto backtesting quanto negociação real, e seu design modular facilita a expansão. Por exemplo, ele pode introduzir ainda mais ajustes dinâmicos de targetProfit e amount, ou adicionar outros indicadores técnicos para melhorar o efeito de filtragem.
Sobre questões do GPT:

O conteúdo a seguir é explicado pela IA:
Nessa estratégia, a filtragem de tendências é obtida por:
var ema = TA.EMA(r, 60)
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] > 0.03) {
cancelAll()
isLock = true
}
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] < 0.02) {
isLock = false
}
if (isLock) {
LogStatus(_D(), "暂停, 检测阈值:", _N(Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2], 3), logStatusMsgBuff)
plotRecords(c, null, null, pos)
Sleep(interval)
continue
}
Bloqueio e liberação de tendência: Comparando a diferença entre o preço atual (ticker.Last) e o valor da EMA da hora anterior, é calculado o percentual pelo qual o preço se desvia da EMA. Math.abs(ticker.Last - ema[ema.length - 2]) / ema[[ema.length - 2] calcula o desvio percentual do preço atual em relação à EMA da hora anterior. Se o desvio exceder 3% (> 0,03), a tendência do mercado será considerada alterada significativamente, e a função cancelAll() será chamada para cancelar todas as ordens pendentes, e isLock será definido como verdadeiro, ou seja, a posição será bloqueada, impedindo futuras negociações. Se o preço se desviar da EMA em menos de 2% (< 0,02), o estado de bloqueio será liberado e isLock será definido como falso.
Suspensão de negociação: Se isLock for verdadeiro (indicando que a posição está bloqueada no momento), nenhuma outra operação de negociação será realizada. O programa gerará registros de log e chamará plotRecords() para desenhar um gráfico para mostrar a tendência atual e o status da posição. Use Sleep(interval) para pausar por um determinado período de tempo e depois continuar o loop.

Parece que algumas tendências podem ser filtradas. Ao ler o código eu mesmo, descobri que a explicação da IA era muito clara, ainda mais clara do que se eu mesmo a tivesse explicado.
Deixando a IA analisar e explicar a estratégia geral e, então, com base na explicação da IA sobre a estratégia geral, gradualmente analisando, desmontando e explicando os detalhes locais da estratégia e explicando as ideias de design. A explicação que recebemos foi relativamente precisa. A IA listou quase todos os detalhes projetados na estratégia sem omissões e conduziu uma análise detalhada por meio de questionamentos adicionais. Essa maneira de aprender todo o pensamento estratégico, detalhes de design de código e aumentar a experiência em design de estratégia é muito útil.
No caminho da negociação quantitativa, a IA pode se tornar uma parceira de aprendizado e crescimento extremamente poderosa para nós. Em vez de depender da IA para gerar estratégias finalizadas com um clique, a IA pode:
Somente esse caminho pode realmente aprimorar nossas capacidades de negociação quantitativa e estabelecer nosso próprio sistema de negociação sistemático. Na plataforma de negociação quantitativa Inventor, podemos aproveitar ao máximo o poder da IA e combiná-la com nossa própria prática para ir mais longe e voar mais alto.