
Nguồn cảm hứng cho chiến lược này xuất phát từ bài đăng về cơ hội của tác giả Zhihu “Dream Dealer” - “Mô hình chênh lệch giá tương quan rủi ro thấp TRUMP và MELANIA”. Bài viết khám phá mối tương quan giá giữa hai hợp đồng được triển khai trên BN (TRUMP và MELANIA) và sử dụng độ trễ thời gian tinh tế giữa hai hợp đồng này để cố gắng nắm bắt những biến động ngắn hạn của thị trường và đạt được sự chênh lệch giá rủi ro thấp. Tiếp theo, chúng tôi sẽ giải thích các nguyên tắc của chiến lược này, logic triển khai mã và khám phá các hướng tối ưu hóa khả thi.
Cần phải có trướcĐể ýVấn đề là chiến lược này tương đương với một công việc giao dịch thủ công. Nó chỉ có một số cơ hội lợi nhuận nhất định sau khi tìm thấy hai cặp giao dịch phù hợp và tuổi thọ lợi nhuận của cặp giao dịch có thể ngắn. Khi phát hiện không có cơ hội lợi nhuận, cần phải dừng chiến lược kịp thời để ngăn chặn việc mất lợi nhuận hoặc thậm chí là thua lỗ.
Cả hợp đồng TRUMP và MELANIA đều được phát hành bởi cùng một nhóm phát hành và có cùng nguồn quỹ kiểm soát, do đó xu hướng giá của chúng hầu như luôn đồng bộ cao. Tuy nhiên, do các yếu tố như thiết kế hợp đồng hoặc thực hiện thị trường, giá của MELANIA có xu hướng chậm hơn giá của TRUMP từ 1-2 giây. Sự chậm trễ nhỏ này tạo cơ hội cho các nhà đầu cơ nắm bắt chênh lệch giá và thực hiện giao dịch sao chép tần suất cao. Nói một cách đơn giản, khi TRUMP biến động nhanh chóng, MELANIA có xu hướng làm theo ngay sau đó. Bằng cách tận dụng sự chậm trễ này, các giao dịch có thể được hoàn thành với rủi ro thấp hơn.


Hiện tượng tương quan tương tự không phải là hiếm trên thị trường tiền điện tử:
Mối tương quan này cung cấp cho các nhà giao dịch tần suất cao và nhà đầu cơ chênh lệch giá các tín hiệu giao dịch ổn định và cơ hội hoạt động rủi ro thấp hơn, nhưng cũng đòi hỏi các chiến lược giao dịch phải cực kỳ nhạy cảm với những thay đổi nhỏ của thị trường và có khả năng phản ứng theo thời gian thực.
Mã này chủ yếu bao gồm nhiều phần, mỗi mô-đun tương ứng với các bước chính trong chiến lược kinh doanh chênh lệch giá.
function GetPosition(pair){
let pos = exchange.GetPosition(pair)
if(pos.length == 0){
return {amount:0, price:0, profit:0}
}else if(pos.length > 1){
throw '不支持双向持仓'
}else if(pos.length == 1){
return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit}
}else{
Log('未获取仓位数据')
return null
}
}
function InitAccount(){
let account = _C(exchange.GetAccount)
let total_eq = account.Equity
let init_eq = 0
if(!_G('init_eq')){
init_eq = total_eq
_G('init_eq', total_eq)
}else{
init_eq = _G('init_eq')
}
return init_eq
}
function CancelPendingOrders() {
orders = exchange.GetOrders(); // 获取订单
for (let order of orders) {
if (order.Status == ORDER_STATE_PENDING) { // 只取消未完成的订单
exchange.CancelOrder(order.Id); // 取消挂单
}
}
}
Hàm chính sử dụng vòng lặp vô hạn để thực hiện liên tục các bước sau:
Thu thập dữ liệu và tính toán thị trường
Mỗi chu kỳ bắt đầu bằngexchange.GetRecords Lấy dữ liệu thị trường của Pair_A và Pair_B tương ứng.
Xác định điều kiện mở cửa và đặt lệnh
Khi không có vị thế hiện tại (position_B.amount == 0) và giao dịch được phép (afterTrade==1):
Logic dừng lợi nhuận và dừng lỗ
Khi vị thế được thiết lập, chiến lược sẽ thiết lập lệnh chốt lời và dừng lỗ tương ứng theo hướng vị thế:
Thống kê lợi nhuận và hồ sơ nhật ký sau khi đóng một vị thế
Sau khi mỗi vị thế được đóng, hệ thống sẽ lấy số liệu thay đổi trong vốn chủ sở hữu tài khoản và đếm số lợi nhuận, số lỗ và số tiền lãi/lỗ tích lũy.
Đồng thời, các bảng và đồ thị được sử dụng để hiển thị thông tin vị trí hiện tại, số liệu thống kê giao dịch và độ trễ chu kỳ theo thời gian thực, thuận tiện cho việc phân tích hiệu ứng chiến lược sau này.
Mặc dù chiến lược này khai thác sự chậm trễ tinh tế giữa hai hợp đồng có mối tương quan cao, vẫn còn nhiều lĩnh vực có thể được cải thiện:
Bài viết này giới thiệu chi tiết các nguyên tắc cơ bản và mã triển khai của chiến lược chênh lệch giá tương quan hợp đồng trễ thời gian ngắn. Từ việc khai thác sự khác biệt về giá tăng và giảm cho đến nắm bắt cơ hội vào lệnh, thiết lập mức dừng lỗ và dừng lãi để quản lý vị thế, chiến lược này tận dụng tối đa mối tương quan cao giữa các tài sản trên thị trường tiền điện tử. Đồng thời, chúng tôi cũng đưa ra một số đề xuất tối ưu hóa, bao gồm điều chỉnh tham số động, lọc tín hiệu, độ mạnh của hệ thống và tối ưu hóa mã, nhằm cải thiện hơn nữa tính ổn định và lợi nhuận của chiến lược trong các ứng dụng thời gian thực.
Mặc dù chiến lược này có nguồn cảm hứng độc đáo và dễ thực hiện, bất kỳ hoạt động kinh doanh chênh lệch giá nào cũng phải được cân nhắc thận trọng trên thị trường tiền điện tử có tần suất biến động cao. Tôi hy vọng bài viết này có thể cung cấp tài liệu tham khảo và nguồn cảm hứng có giá trị cho những người bạn quan tâm đến giao dịch định lượng và chiến lược chênh lệch giá.
Lưu ý: Môi trường thử nghiệm chiến lược là giao dịch mô phỏng OKX và các chi tiết cụ thể có thể được sửa đổi cho các sàn giao dịch khác nhau
function GetPosition(pair){
let pos = exchange.GetPosition(pair)
if(pos.length == 0){
return {amount:0, price:0, profit:0}
}else if(pos.length > 1){
throw '不支持双向持仓'
}else if(pos.length == 1){
return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit}
}else{
Log('未获取仓位数据')
return null
}
}
function InitAccount(){
let account = _C(exchange.GetAccount)
let total_eq = account.Equity
let init_eq = 0
if(!_G('init_eq')){
init_eq = total_eq
_G('init_eq', total_eq)
}else{
init_eq = _G('init_eq')
}
return init_eq
}
function CancelPendingOrders() {
orders = exchange.GetOrders(); // 获取订单
for (let order of orders) {
if (order.Status == ORDER_STATE_PENDING) { // 只取消未完成的订单
exchange.CancelOrder(order.Id); // 取消挂单
}
}
}
var pair_a = Pair_A + "_USDT.swap";
var pair_b = Pair_B + "_USDT.swap";
function main() {
exchange.IO('simulate', true);
LogReset(0);
Log('策略开始运行')
var precision = exchange.GetMarkets();
var ratio = 0
var takeProfitOrderId = null;
var stopLossOrderId = null;
var successCount = 0;
var lossCount = 0;
var winMoney = 0;
var failMoney = 0;
var afterTrade = 1;
var initEq = InitAccount();
var curEq = initEq
var pricePrecision = precision[pair_b].PricePrecision;
while (true) {
try{
let startLoopTime = Date.now();
let position_B = GetPosition(pair_b);
let new_r_pairB = exchange.GetRecords(pair_b, 1).slice(-1)[0];
if (!new_r_pairB || !position_B) {
Log('跳过当前循环');
continue;
}
// 合并交易条件:检查是否可以开仓并进行交易
if (afterTrade == 1 && position_B.amount == 0) {
let new_r_pairA = exchange.GetRecords(pair_a, 1).slice(-1)[0];
if (!new_r_pairA ) {
Log('跳过当前循环');
continue;
}
ratio = (new_r_pairA.Close - new_r_pairA.Open) / new_r_pairA.Open - (new_r_pairB.Close - new_r_pairB.Open) / new_r_pairB.Open;
if (ratio > diffLevel) {
CancelPendingOrders();
Log('实时ratio:', ratio, '买入:', pair_b, position_B.amount);
exchange.CreateOrder(pair_b, "buy", -1, Trade_Number);
afterTrade = 0;
} else if (ratio < -diffLevel) {
CancelPendingOrders();
Log('实时ratio:', ratio, '卖出:', pair_b, position_B.amount);
exchange.CreateOrder(pair_b, "sell", -1, Trade_Number);
afterTrade = 0;
}
}
// 判断止盈止损
if (position_B.amount > 0 && takeProfitOrderId == null && stopLossOrderId == null && afterTrade == 0) {
Log('多仓持仓价格:', position_B.price, '止盈价格:', position_B.price * (1 + stopProfitLevel), '止损价格:', position_B.price * (1 - stopLossLevel));
takeProfitOrderId = exchange.CreateOrder(pair_b, "closebuy", position_B.price * (1 + stopProfitLevel), position_B.amount);
Log('止盈订单:', takeProfitOrderId);
}
if (position_B.amount > 0 && takeProfitOrderId != null && stopLossOrderId == null && new_r_pairB.Close < position_B.price * (1 - stopLossLevel) && afterTrade == 0) {
CancelPendingOrders();
takeProfitOrderId = null
Log('多仓止损');
stopLossOrderId = exchange.CreateOrder(pair_b, "closebuy", -1, position_B.amount);
Log('多仓止损订单:', stopLossOrderId);
}
if (position_B.amount < 0 && takeProfitOrderId == null && stopLossOrderId == null && afterTrade == 0) {
Log('空仓持仓价格:', position_B.price, '止盈价格:', position_B.price * (1 - stopProfitLevel), '止损价格:', position_B.price * (1 + stopLossLevel));
takeProfitOrderId = exchange.CreateOrder(pair_b, "closesell", position_B.price * (1 - stopProfitLevel), -position_B.amount);
Log('止盈订单:', takeProfitOrderId, '当前价格:', new_r_pairB.Close );
}
if (position_B.amount < 0 && takeProfitOrderId != null && stopLossOrderId == null && new_r_pairB.Close > position_B.price * (1 + stopLossLevel) && afterTrade == 0) {
CancelPendingOrders();
takeProfitOrderId = null
Log('空仓止损');
stopLossOrderId = exchange.CreateOrder(pair_b, "closesell", -1, -position_B.amount);
Log('空仓止损订单:', stopLossOrderId);
}
// 平市价单未完成
if (takeProfitOrderId == null && stopLossOrderId != null && afterTrade == 0) {
let stoplosspos = GetPosition(pair_b)
if(stoplosspos.amount > 0){
Log('平多仓市价单未完成')
exchange.CreateOrder(pair_b, 'closebuy', -1, stoplosspos.amount)
}
if(stoplosspos.amount < 0){
Log('平空仓市价单未完成')
exchange.CreateOrder(pair_b, 'closesell', -1, -stoplosspos.amount)
}
}
// 未平仓完毕
if (Math.abs(position_B.amount) < Trade_Number && Math.abs(position_B.amount) > 0 && afterTrade == 0){
Log('未平仓完毕')
if(position_B.amount > 0){
exchange.CreateOrder(pair_b, 'closebuy', -1, position_B.amount)
}else{
exchange.CreateOrder(pair_b, 'closesell', -1, -position_B.amount)
}
}
// 计算盈亏
if (position_B.amount == 0 && afterTrade == 0) {
if (stopLossOrderId != null || takeProfitOrderId != null) {
stopLossOrderId = null;
takeProfitOrderId = null;
let afterEquity = exchange.GetAccount().Equity;
let curAmount = afterEquity - curEq;
curEq = afterEquity
if (curAmount > 0) {
successCount += 1;
winMoney += curAmount;
Log('盈利金额:', curAmount);
} else {
lossCount += 1;
failMoney += curAmount;
Log('亏损金额:', curAmount);
}
afterTrade = 1;
}
}
if (startLoopTime % 10 == 0) { // 每 10 次循环记录一次
let curEquity = exchange.GetAccount().Equity
// 输出交易信息表
let table = {
type: "table",
title: "交易信息",
cols: [
"初始权益", "当前权益", Pair_B + "仓位", Pair_B + "持仓价", Pair_B + "收益", Pair_B + "价格",
"盈利次数", "盈利金额", "亏损次数", "亏损金额", "胜率", "盈亏比"
],
rows: [
[
_N(_G('init_eq'), 2), // 初始权益
_N(curEquity, 2), // 当前权益
_N(position_B.amount, 1), // Pair B 仓位
_N(position_B.price, pricePrecision), // Pair B 持仓价
_N(position_B.profit, 1), // Pair B 收益
_N(new_r_pairB.Close, pricePrecision), // Pair B 价格
_N(successCount, 0), // 盈利次数
_N(winMoney, 2), // 盈利金额
_N(lossCount, 0), // 亏损次数
_N(failMoney, 2), // 亏损金额
_N(successCount + lossCount === 0 ? 0 : successCount / (successCount + lossCount), 2), // 胜率
_N(failMoney === 0 ? 0 : winMoney / failMoney * -1, 2) // 盈亏比
]
]
};
$.PlotMultLine("ratio plot", "幅度变化差值", ratio, startLoopTime);
$.PlotMultHLine("ratio plot", diffLevel, "差价上限", "red", "ShortDot");
$.PlotMultHLine("ratio plot", -diffLevel, "差价下限", "blue", "ShortDot");
LogStatus("`" + JSON.stringify(table) + "`");
LogProfit(curEquity - initEq, '&')
}
}catch(e){
Log('策略出现错误:', e)
}
Sleep(200);
}
}