人工知能(AI)技術の急速な発展により、多くの分野で非常に高い効率性と創造性を発揮しています。クオンツ取引は高度な技術を要する分野であるため、当然ながら AI の応用も積極的に検討されています。しかし、実際には、完全で安定した、持続的に収益性の高い取引戦略を直接生成するために AI だけに頼るには、依然として大きな課題があることがわかります。
特にプラットフォームの新規ユーザーの場合、プログラミングスキルが弱いため、取引のアイデアを戦略コードに実装することが困難です。現時点では、AIにアイデアを伝えて戦略を出力させることは可能です。しかし、導入効果は期待通りではありませんでした。 AIが生成したコードを持って質問に来るユーザーによく遭遇しますが、AIが生成した戦略が一目でわかることもあります。現段階では AI によって生成された戦略コードにはまだ多くの問題があるため、このように AI を使用すると問題が解決されないだけでなく、初心者にさらなる混乱と問題をもたらすことになります。学べば学ぶほど混乱し、結局「最初から諦めてしまった」のです。
個人的には、AI 直接出力戦略の現在の問題には、主に 2 つの原因があると考えています。
- 各人の戦略要件の説明のロジック、正確性、プロセスの明確さは大きく異なり、AI モデルによるこれらの自然言語の理解には偏りが生じます。
- AIビッグモデルはプラットフォームの情報に基づいてトレーニングされていないため、プラットフォームの機能やAPIなどに対する理解が限られており、生成される情報の精度も限られています。
では、もっと効率的な適用方法はあるのでしょうか?この記事では、AI を活用して既存の戦略を学習し、戦略設計を理解し、重要な詳細と手法を抽出し、さらにその有効性と改善の余地を分析するという新しい考え方を共有したいと思います。この方法は、戦略設計の本質をより早く把握するのに役立つだけでなく、定量的な取引レベルを体系的に向上させるのにも役立ちます。
AI を活用することで、AI は特定のコード分析を比較的正確に理解できるようになります。これは、AI にとってコード データは「1 は 1、2 は 2」であり、自然言語による記述要件によって生じる論理的な混乱、曖昧さ、その他の問題がなくなるためです。そこで、AI の利点を活用して手作業の負荷を軽減し、手作業の利点を最大限に活用してみてはいかがでしょうか。
AI を使用して逆学習戦略を実行するにはどうすればよいでしょうか?
それは次のステップに分けられます。
-
既存の戦略を選択
それは、自分で書いたもの、オープンソースのもの、または発明者の定量プラットフォーム上の優れた戦略サンプルである可能性があります。 -
AIを活用して戦略を説明しましょう
全体的な考え方を理解する
各部品の機能モジュールを整理する
使用される指標、パラメータ、取引ロジックを明確にする
-
AIが戦略の長所と短所を分析できるように、さらに質問をする
どのような市場状況でこの戦略のパフォーマンスが向上するのでしょうか?
考えられるリスクポイントは何ですか?
どの領域を最適化および改善できますか?
-
自分の考えに基づいて検証し調整する
異なる製品と期間でのバックテスト
追加のフィルターやリスク管理対策を追加する
パフォーマンスの変化を観察し、独自の洞察を形成する
練習する
AI に戦略を学習させて説明させ、それが私たちの期待に応えているかどうかを確認してみましょう。定量化を学ぶのに役立ちます。
ポリシーサンプル
EMAトレンドフィルタリングに基づく段階的なポジション増加取引戦略の設計と実装
戦略アドレス: https://www.fmz.com/strategy/492116
javascript
/*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 に説明させ、学習効率を向上させるのも良いでしょう。
AIによる説明
ここでは GPT を使用しており、次のコンテンツは AI によって説明されています。
-
概要
この記事では、EMA(指数移動平均)トレンドフィルタリングに基づいた、段階的にポジションを増やす取引戦略を紹介します。
この戦略は主に Binance Futures (Futures_Binance) で使用され、1 時間のバックテストをサポートし、1 分間の K ライン データ集約に基づいています。
価格とEMAの偏差をリアルタイムで監視することで、取引モード(通常取引/一時停止取引)を動的に切り替え、安定した市場では徐々にポジションを増やし、異常な変動時には自動的にポジションを一時停止してリスクを回避します。 -
- 戦略ロジック
-
- トレンドフィルタリング(ロック位置制御)
直近 1 時間のローソク足データの 60 期間 EMA を計算します。
現在の価格が EMA から 3% 以上乖離している場合は、注文の発注を一時停止し、保留中の注文をキャンセルします。
偏差が2%以内に戻ると、通常の取引が再開されます。
トレンドフィルタリングにより、不安定な市場状況でポジションが頻繁に増加することによって引き起こされる清算のリスクを回避できます。
- トレンドフィルタリング(ロック位置制御)
-
- ポジション追加ロジック(徐々にポジションを追加)
最初にポジションがない場合、買い安値注文と売り高値注文の 2 つの保留注文が同時に出されます。
注文価格:
買い注文は現在の価格(targetProfit/5 距離)より下に出されます
売り注文は現在の価格(targetProfit/5距離)より上に出されます
保留注文が実行されると、ポジションが段階的に増加します。
買い注文が執行された場合は、引き続きより低い価格で次の買い注文を出し、既存のポジションに対して売りの利益確定注文を設定します。
売り注文が執行された場合は、さらに高い価格で次の売り注文を出し続けて、既存のポジションに対して買いのストップ利益注文を設定します。
追加されるポジションの量は、2 倍または固定量に設定できます。
ポジションの追加数が maxAddCounter に達すると、この戦略では強制的に清算することを選択できます。
- ポジション追加ロジック(徐々にポジションを追加)
-
- ポジション管理と資本保護
初期の総資産 (totalEq) に基づいて、開かれる各ポジションの金額を設定します。
USDT 金額による契約数の見積りをサポートします (原価格に基づいて注文数量を自動的に計算します)。
アカウントの残高が一定の割合(準備金)よりも大きいことを確認します。残高が不足している場合は取引を停止します。
- ポジション管理と資本保護
-
- コア機能とモジュールの紹介
-
- 口座残高合計を取得する
getTotalEquity 関数は、Binance Futures (Futures_Binance) および OKEX V5 (Futures_OKCoin) 用にカプセル化されています。
異なる取引所の API の違いと互換性があり、アカウントの現在の総資産 (USDT 建て) を均一に返します。
- 口座残高合計を取得する
-
- 注文の発注とキャンセルのモジュール
trade(direction, price, amount): 統一された注文インターフェースをカプセル化します。
cancelAll(): 保留中の注文が多すぎることによるリスクの蓄積を防ぐため、保留中の注文をすべてキャンセルします。
- 注文の発注とキャンセルのモジュール
-
- ロングポジション、ショートポジション、クローズポジション
openLong(価格、金額): オープンロング。
openShort(price, amount): ショートポジションを開きます。
coverLong(price, amount): ロングに近い。
coverShort(価格、金額): 空です。
- ロングポジション、ショートポジション、クローズポジション
-
- 追加されたポジションの数とステータスレコード
使用する_G() は、切断および再起動後にポジション追加ステータスが失われないように、ポジション追加回数 addCounter を永続的に記録します。
LogStatus を使用して、リアルタイムのアカウント情報、保留中の注文のステータス、およびポジション情報を動的に表示します。
- 追加されたポジションの数とステータスレコード
-
- チャート描画
KLineChart を使用して、買い注文価格、売り注文価格、平均ポジション価格などの主要な線を描画し、視覚的なバックテストとリアルタイム監視を支援します。
- チャート描画
-
- 戦略フローチャート
textflowchart TD 开始 --> 初始化参数 初始化参数 --> 账户余额检查 账户余额检查 --> 计算EMA 计算EMA --> 判断是否锁仓 判断是否锁仓 -->|是| 暂停交易 判断是否锁仓 -->|否| 正常交易 正常交易 --> 是否有持仓 是否有持仓 -->|无| 首次挂单 是否有持仓 -->|有| 按持仓方向加仓与止盈挂单 首次挂单 --> 等待成交 按持仓方向加仓与止盈挂单 --> 等待成交 等待成交 --> 挂单成交检测 挂单成交检测 --> 成交后调整 成交后调整 --> 更新加仓次数 更新加仓次数 --> 是否超出最大加仓次数 是否超出最大加仓次数 -->|是| 平仓 是否超出最大加仓次数 -->|否| 继续交易 -
5つ目 結論
EMA フィルタリングに基づくこの段階的なポジション増加戦略は、収益とリスク管理の両方を考慮しており、変動の激しい市場や変動の弱い市場での運用に適しています。
ポジションを追加する柔軟な方法とトレンド一時停止メカニズムを通じて、清算の確率を効果的に低減し、資本の使用効率を向上させることができます。
バックテストと実際の取引の両方をサポートし、モジュール設計により拡張が容易です。たとえば、targetProfit と amount の動的な調整をさらに導入したり、他のテクニカル指標を追加してフィルタリング効果を高めたりすることもできます。- より進んだ提案をしましょうか?例えば:
双方向ポジションアップ(双方向ポジション)への改善方法
ポジション増加率を動的に調整する方法
リスク管理のストップロスロジックを組み込むにはどうすればよいでしょうか?
- より進んだ提案をしましょうか?例えば:
現地の質問/説明
GPT に関する質問について:
以下の内容はAIによって説明されます。
この戦略では、トレンド フィルタリングは次のように実現されます。
javascript
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
}
-
コード分析
EMAトレンドフィルター:
TA.EMA(r, 60) は、過去 60 時間の指数移動平均 (EMA) を計算するために使用されます。 r は exchange.GetRecords によって取得された K ラインの履歴データであり、各データ ポイントは 1 時間の価格情報を表します。 EMA 配列には、各時間の EMA 値が格納されます。[ema.length - 2]は、現在の時点での前時間のEMA値を表します。トレンドのロックとリリース:
現在の価格 (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 のパワーを最大限に活用し、それを自身の実践と組み合わせて、さらに前進し、より高く飛躍することができます。
- 1



