[TOC]

人工知能(AI)技術の急速な発展により、多くの分野で非常に高い効率性と創造性を発揮しています。クオンツ取引は高度な技術を要する分野であるため、当然ながら AI の応用も積極的に検討されています。しかし、実際には、完全で安定した、持続的に収益性の高い取引戦略を直接生成するために AI だけに頼るには、依然として大きな課題があることがわかります。
特にプラットフォームの新規ユーザーの場合、プログラミングスキルが弱いため、取引のアイデアを戦略コードに実装することが困難です。現時点では、AIにアイデアを伝えて戦略を出力させることは可能です。しかし、導入効果は期待通りではありませんでした。 AIが生成したコードを持って質問に来るユーザーによく遭遇しますが、AIが生成した戦略が一目でわかることもあります。現段階では AI によって生成された戦略コードにはまだ多くの問題があるため、このように AI を使用すると問題が解決されないだけでなく、初心者にさらなる混乱と問題をもたらすことになります。学べば学ぶほど混乱し、結局「最初から諦めてしまった」のです。
個人的には、AI 直接出力戦略の現在の問題には、主に 2 つの原因があると考えています。
では、もっと効率的な適用方法はあるのでしょうか?この記事では、AI を活用して既存の戦略を学習し、戦略設計を理解し、重要な詳細と手法を抽出し、さらにその有効性と改善の余地を分析するという新しい考え方を共有したいと思います。この方法は、戦略設計の本質をより早く把握するのに役立つだけでなく、定量的な取引レベルを体系的に向上させるのにも役立ちます。
AI を活用することで、AI は特定のコード分析を比較的正確に理解できるようになります。これは、AI にとってコード データは「1 は 1、2 は 2」であり、自然言語による記述要件によって生じる論理的な混乱、曖昧さ、その他の問題がなくなるためです。そこで、AI の利点を活用して手作業の負荷を軽減し、手作業の利点を最大限に活用してみてはいかがでしょうか。
それは次のステップに分けられます。
既存の戦略を選択 それは、自分で書いたもの、オープンソースのもの、または発明者の定量プラットフォーム上の優れた戦略サンプルである可能性があります。
AIを活用して戦略を説明しましょう
全体的な考え方を理解する
各部品の機能モジュールを整理する
使用される指標、パラメータ、取引ロジックを明確にする
どのような市場状況でこの戦略のパフォーマンスが向上するのでしょうか?
考えられるリスクポイントは何ですか?
どの領域を最適化および改善できますか?
異なる製品と期間でのバックテスト
追加のフィルターやリスク管理対策を追加する
パフォーマンスの変化を観察し、独自の洞察を形成する
AI に戦略を学習させて説明させ、それが私たちの期待に応えているかどうかを確認してみましょう。定量化を学ぶのに役立ちます。
EMAトレンドフィルタリングに基づく段階的なポジション増加取引戦略の設計と実装 戦略アドレス: 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()
}
FMZ プラットフォームを初めて学ぶ人にとって、このようなコードの山を見ると途方に暮れてしまうかもしれません。コードを 1 行ずつ勉強する代わりに、(怠けて)コードを AI に渡して、AI に説明させ、学習効率を向上させるのも良いでしょう。
ここでは GPT を使用しており、次のコンテンツは AI によって説明されています。
概要 この記事では、EMA(指数移動平均)トレンドフィルタリングに基づいた、段階的にポジションを増やす取引戦略を紹介します。 この戦略は主に Binance Futures (Futures_Binance) で使用され、1 時間のバックテストをサポートし、1 分間の K ライン データ集約に基づいています。 価格とEMAの偏差をリアルタイムで監視することで、取引モード(通常取引/一時停止取引)を動的に切り替え、安定した市場では徐々にポジションを増やし、異常な変動時には自動的にポジションを一時停止してリスクを回避します。
flowchart TD
开始 --> 初始化参数
初始化参数 --> 账户余额检查
账户余额检查 --> 计算EMA
计算EMA --> 判断是否锁仓
判断是否锁仓 -->|是| 暂停交易
判断是否锁仓 -->|否| 正常交易
正常交易 --> 是否有持仓
是否有持仓 -->|无| 首次挂单
是否有持仓 -->|有| 按持仓方向加仓与止盈挂单
首次挂单 --> 等待成交
按持仓方向加仓与止盈挂单 --> 等待成交
等待成交 --> 挂单成交检测
挂单成交检测 --> 成交后调整
成交后调整 --> 更新加仓次数
更新加仓次数 --> 是否超出最大加仓次数
是否超出最大加仓次数 -->|是| 平仓
是否超出最大加仓次数 -->|否| 继续交易
5つ目 結論 EMA フィルタリングに基づくこの段階的なポジション増加戦略は、収益とリスク管理の両方を考慮しており、変動の激しい市場や変動の弱い市場での運用に適しています。 ポジションを追加する柔軟な方法とトレンド一時停止メカニズムを通じて、清算の確率を効果的に低減し、資本の使用効率を向上させることができます。 バックテストと実際の取引の両方をサポートし、モジュール設計により拡張が容易です。たとえば、targetProfit と amount の動的な調整をさらに導入したり、他のテクニカル指標を追加してフィルタリング効果を高めたりすることもできます。
GPT に関する質問について:

以下の内容はAIによって説明されます。
この戦略では、トレンド フィルタリングは次のように実現されます。
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
}
トレンドのロックとリリース: 現在の価格 (ticker.Last) と前時間の EMA 値の差を比較することにより、価格が EMA から逸脱するパーセンテージが計算されます。 Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2]は、前時間のEMAからの現在の価格のパーセンテージ偏差を計算します。 偏差が 3% (> 0.03) を超えると、市場のトレンドが大きく変化したとみなされ、cancelAll() 関数が呼び出されてすべての保留中の注文がキャンセルされ、isLock が true に設定され、ポジションがロックされて、それ以上の取引ができなくなります。 価格が EMA から 2% 未満 (< 0.02) 逸脱した場合、ロック状態は解除され、isLock は false に設定されます。
取引停止: isLock が true の場合(ポジションが現在ロックされていることを示します)、それ以上の取引操作は実行されません。 プログラムはログ レコードを出力し、plotRecords() を呼び出して、現在の傾向と位置の状態を示すチャートを描画します。 Sleep(interval) を使用すると、一定時間一時停止してからループを続行できます。

いくつかの傾向を除外できるようです。自分でコードを読んでみると、AI の説明は非常に明確で、自分で説明するよりもさらに明確であることがわかりました。
AIに全体戦略を分析・説明させ、その後AIによる全体戦略の説明に基づいて、戦略の局所的な詳細や設計思想を段階的に分析・分解・説明していきます。私たちが受けた説明は比較的正確でした。 AIは戦略で設計されたほぼすべての詳細を漏れなくリスト化し、さらに質問することで詳細な分析を行いました。全体的な戦略の考え方、コード設計の詳細を学び、戦略設計の経験を増やすこの方法はすべて非常に役立ちます。
定量取引の道において、AI は私たちにとって非常に強力な学習および成長のパートナーになることができます。 AI に頼って 1 回のクリックで完成した戦略を生成するのではなく、AI は次のことを行うことができます。
この道こそが、私たちの定量的取引能力を真に強化し、独自の体系的な取引システムを確立できる道なのです。 Inventor Quantitative Trading Platform では、AI のパワーを最大限に活用し、それを自身の実践と組み合わせて、さらに前進し、より高く飛躍することができます。