Đối với những người mới bắt đầu thiết kế chiến lược, các chiến lược đầu cơ là một chiến lược thực tập tốt. Bài viết này thực hiện một chiến lược đầu cơ tiền kỹ thuật số đơn giản nhưng thực tế, hy vọng sẽ giúp những người mới bắt đầu học một số kinh nghiệm thiết kế.
Trước tiên, hãy nói rõ rằng chiến lược sắp được thiết kế này là một chiến lược đầu cơ tiền mặt kỹ thuật số, chúng tôi đã thiết kế một cách đơn giản nhất, chỉ bán trên hai sàn giao dịch tiền mặt, mua trên sàn giao dịch thấp hơn để kiếm được chênh lệch.
Giá, số lượng, sàn giao dịch có giới hạn về độ chính xác khi đặt hàng, và cũng có giới hạn về số lượng đơn đặt hàng tối thiểu. Ngoài việc có giới hạn tối thiểu, chiến lược ngoài giới hạn tối thiểu trong việc bảo hiểm cũng phải xem xét số lượng đơn đặt hàng tối đa được đặt hàng một lần, nếu đơn đặt hàng quá lớn thì sẽ không có đủ số lượng đơn đặt hàng. Bạn cũng cần xem xét cách chuyển đổi tỷ giá ngoại hối nếu hai đồng tiền được giao dịch khác nhau.
Trên cơ sở những cân nhắc này, chiến lược cần thiết phải thiết kế một vài thông số:
hedgeDiffPrice
, Khi giá vượt quá giá trị này, kích hoạt hoạt động bảo hiểm.minHedgeAmount
Số tiền được bảo hiểm là số tiền tối thiểu có thể được bảo hiểm.maxHedgeAmount
Số tiền ký quỹ được tính theo số tiền ký quỹ.pricePrecisionA
, Định giá chính xác của giao dịch A (số số nhỏ) ⇒amountPrecisionA
, Đơn vị chính xác của sàn giao dịch A (số số nhỏ).pricePrecisionB
Định giá chính xác của sàn giao dịch B (độ số nhỏ)amountPrecisionB
, Đơn vị chính xác của sàn giao dịch B (số số nhỏ) ⇒rateA
, Chuyển đổi tỷ giá đối tượng giao dịch đầu tiên được thêm vào, mặc định 1 không chuyển đổi.rateB
, chuyển đổi tỷ giá đối tượng giao dịch thứ hai được thêm vào, mặc định 1 không chuyển đổi.Chiến lược chống rủi ro đòi hỏi phải giữ số tiền của hai tài khoản không thay đổi (tức là không nắm giữ bất kỳ vị trí hướng nào, giữ trung tính), vì vậy cần một logic cân bằng trong chiến lược luôn phát hiện cân bằng. Khi phát hiện cân bằng, chúng ta không thể tránh lấy dữ liệu tài sản của hai sàn giao dịch. Chúng ta cần viết một hàm để sử dụng.
function updateAccs(arrEx) {
var ret = []
for (var i = 0 ; i < arrEx.length ; i++) {
var acc = arrEx[i].GetAccount()
if (!acc) {
return null
}
ret.push(acc)
}
return ret
}
Nếu lệnh không được giao dịch sau đó, chúng ta cần hủy bỏ đúng thời điểm, không thể để lệnh bị treo. Hoạt động này đều cần được xử lý trong mô-đun cân bằng hoặc trong logic đầu cơ, vì vậy cần thiết phải thiết kế một hàm hủy bỏ toàn bộ lệnh.
function cancelAll() {
_.each(exchanges, function(ex) {
while (true) {
var orders = _C(ex.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
ex.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
}
})
}
Khi cân bằng số tiền, chúng ta cần tìm giá tích lũy đến số tiền nhất định trong một số dữ liệu sâu, vì vậy cần một hàm như vậy để xử lý.
function getDepthPrice(depth, side, amount) {
var arr = depth[side]
var sum = 0
var price = null
for (var i = 0 ; i < arr.length ; i++) {
var ele = arr[i]
sum += ele.Amount
if (sum >= amount) {
price = ele.Price
break
}
}
return price
}
Sau đó, chúng ta cần phải thiết kế và viết các hoạt động đặt hàng theo lệnh cụ thể, chúng ta cần thiết kế các lệnh theo dõi cùng nhau:
function hedge(buyEx, sellEx, price, amount) {
var buyRoutine = buyEx.Go("Buy", price, amount)
var sellRoutine = sellEx.Go("Sell", price, amount)
Sleep(500)
buyRoutine.wait()
sellRoutine.wait()
}
Cuối cùng, chúng ta sẽ hoàn thành việc thiết kế các hàm cân bằng, các hàm cân bằng hơi phức tạp.
function keepBalance(initAccs, nowAccs, depths) {
var initSumStocks = 0
var nowSumStocks = 0
_.each(initAccs, function(acc) {
initSumStocks += acc.Stocks + acc.FrozenStocks
})
_.each(nowAccs, function(acc) {
nowSumStocks += acc.Stocks + acc.FrozenStocks
})
var diff = nowSumStocks - initSumStocks
// 计算币差
if (Math.abs(diff) > minHedgeAmount && initAccs.length == nowAccs.length && nowAccs.length == depths.length) {
var index = -1
var available = []
var side = diff > 0 ? "Bids" : "Asks"
for (var i = 0 ; i < nowAccs.length ; i++) {
var price = getDepthPrice(depths[i], side, Math.abs(diff))
if (side == "Bids" && nowAccs[i].Stocks > Math.abs(diff)) {
available.push(i)
} else if (price && nowAccs[i].Balance / price > Math.abs(diff)) {
available.push(i)
}
}
for (var i = 0 ; i < available.length ; i++) {
if (index == -1) {
index = available[i]
} else {
var priceIndex = getDepthPrice(depths[index], side, Math.abs(diff))
var priceI = getDepthPrice(depths[available[i]], side, Math.abs(diff))
if (side == "Bids" && priceIndex && priceI && priceI > priceIndex) {
index = available[i]
} else if (priceIndex && priceI && priceI < priceIndex) {
index = available[i]
}
}
}
if (index == -1) {
Log("无法平衡")
} else {
// 平衡下单
var price = getDepthPrice(depths[index], side, Math.abs(diff))
if (price) {
var tradeFunc = side == "Bids" ? exchanges[index].Sell : exchanges[index].Buy
tradeFunc(price, Math.abs(diff))
} else {
Log("价格无效", price)
}
}
return false
} else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
Log("错误:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
return true
} else {
return true
}
}
Sau khi thiết kế các hàm này theo nhu cầu của chính sách, bạn có thể bắt đầu thiết kế các hàm chính của chính sách.
Phương pháp trên FMZ là từmain
Chức năng bắt đầu thực hiện tại.main
Trong phần bắt đầu của hàm, chúng ta sẽ làm một số công việc khởi tạo chính sách.
Tên đối tượng giao dịch Vì nhiều hoạt động trong chiến lược được sử dụng cho các đối tượng giao dịch, chẳng hạn như lấy thị trường, đặt hàng, v.v. Vì vậy, việc sử dụng một tên dài mỗi lần sẽ rất khó khăn, mẹo nhỏ là thay thế bằng một tên đơn giản, ví dụ:
var exA = exchanges[0]
var exB = exchanges[1]
Một số người cho rằng việc viết code sau đó sẽ dễ dàng hơn.
Định giá, thiết kế chính xác
// 精度,汇率设置
if (rateA != 1) {
// 设置汇率A
exA.SetRate(rateA)
Log("交易所A设置汇率:", rateA, "#FF0000")
}
if (rateB != 1) {
// 设置汇率B
exB.SetRate(rateB)
Log("交易所B设置汇率:", rateB, "#FF0000")
}
exA.SetPrecision(pricePrecisionA, amountPrecisionA)
exB.SetPrecision(pricePrecisionB, amountPrecisionB)
Nếu các thông số ngoại hốirateA
、rateB
Có cài đặt là 1 (bằng mặc định là 1), đó làrateA != 1
HoặcrateB != 1
Không kích hoạt, do đó không thiết lập chuyển đổi tỷ giá.
Đặt lại tất cả dữ liệu
Đôi khi, khi bắt đầu chính sách, bạn cần xóa tất cả các nhật ký, dữ liệu ghi trống. Bạn có thể thiết kế một tham số giao diện chính sách.isReset
, sau đó thiết kế phần đặt lại mã được khởi tạo trong chính sách, ví dụ:
if (isReset) { // 当isReset为真时重置数据
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
Khôi phục dữ liệu tài khoản ban đầu, cập nhật dữ liệu tài khoản hiện tại
Để đánh giá sự cân bằng, chiến lược cần phải ghi lại liên tục tình hình tài sản tài khoản ban đầu được sử dụng và so sánh với hiện tại.nowAccs
Đây là một biến được sử dụng để ghi lại dữ liệu tài khoản hiện tại bằng cách sử dụng các hàm mà chúng tôi vừa thiết kế.updateAccs
Nhìn vào tài khoản của các sàn giao dịch hiện tại.initAccs
Sử dụng để ghi lại tình trạng tài khoản ban đầu (dữ liệu về số tiền của sàn A và sàn B, số tiền được định giá, v.v.)initAccs
Sử dụng đầu tiên_G()
Phục hồi chức năng ((_G) chức năng ghi lại dữ liệu vĩnh viễn và có thể quay lại dữ liệu đã ghi lại, xem tài liệu API:Liên kết), nếu không có truy vấn, hãy gán và sử dụng thông tin tài khoản hiện tại_G
Các chức năng ghi chép.
Ví dụ:
var nowAccs = _C(updateAccs, exchanges)
var initAccs = _G("initAccs")
if (!initAccs) {
initAccs = nowAccs
_G("initAccs", initAccs)
}
Mã trong vòng tròn chính là quá trình mà logic chiến lược thực hiện mỗi vòng, và việc thực hiện lặp đi lặp lại liên tục tạo thành vòng tròn chính. Hãy xem xét các quá trình mà chương trình trong vòng tròn chính thực hiện mỗi lần.
Thu thập dữ liệu thị trường để đánh giá hiệu quả của dữ liệu thị trường
var ts = new Date().getTime()
var depthARoutine = exA.Go("GetDepth")
var depthBRoutine = exB.Go("GetDepth")
var depthA = depthARoutine.wait()
var depthB = depthBRoutine.wait()
if (!depthA || !depthB || depthA.Asks.length == 0 || depthA.Bids.length == 0 || depthB.Asks.length == 0 || depthB.Bids.length == 0) {
Sleep(500)
continue
}
Ở đây bạn có thể thấy các hàm đồng thời sử dụng nền tảng FMZexchange.Go
, tạo ra một cuộc gọiGetDepth()
Đối tượng đồng thời của giao diệndepthARoutine
、depthBRoutine
│ Khi tạo hai đối tượng đồng thời, hãy gọiGetDepth()
Một giao diện cũng xảy ra ngay lập tức, khi cả hai yêu cầu thu thập dữ liệu sâu được gửi đến sàn giao dịch.
Sau đó gọidepthARoutine
、depthBRoutine
đối tượngwait()
Cách thu thập dữ liệu sâu.
Sau khi có được dữ liệu sâu, dữ liệu sâu cần được kiểm tra để đánh giá hiệu quả của nó.continue
Câu nói thực hiện lại vòng tròn chính.
Sử dụng价差值
Các tham số là差价比例
Các tham số?
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Các tham số của FMZ có thể dựa trên một số tham số.Hiển thịHoặcẩn náuVì vậy, chúng ta có thể làm cho một tham số để quyết định sử dụng价格差
Hay là差价比例
。
Thêm một tham số vào tham số giao diện chiến lượcdiffAsPercentage
❖ Hai tham số khác dựa trên tham số này hiển thị hoặc ẩn được đặt là:hedgeDiffPrice@!diffAsPercentage
KhidiffAsPercentage
Để hiển thị tham số này.hedgeDiffPercentage@diffAsPercentage
KhidiffAsPercentage
Trả lời là đúng.
Sau khi thiết kế xong, chúng tôi chọndiffAsPercentage
Các tham số, đó là tỷ lệ chênh lệch giá như một điều kiện kích hoạt rủi ro; không chọndiffAsPercentage
Các tham số là các điều kiện kích hoạt rủi ro theo giá khác nhau.
Xác định các điều kiện kích hoạt rủi ro
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B 盘口条件满足
var price = (depthA.Bids[0].Price + depthB.Asks[0].Price) / 2
var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance / price > minHedgeAmount) {
amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance / price, maxHedgeAmount)
Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks) // 提示信息
hedge(exB, exA, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
} else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPrice && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) { // B -> A 盘口条件满足
var price = (depthB.Bids[0].Price + depthA.Asks[0].Price) / 2
var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance / price > minHedgeAmount) {
amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance / price, maxHedgeAmount)
Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks) // 提示信息
hedge(exA, exB, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Có một số điều kiện kích hoạt rủi ro như sau:
1, Đáp ứng đầu tiên với chênh lệch bảo hiểm, và chỉ có thể bảo hiểm khi chênh lệch của giao dịch đáp ứng các tham số chênh lệch được thiết lập.
2, giá trị giao dịch có thể được bảo hiểm đáp ứng giá trị bảo hiểm tối thiểu được đặt trên tham số, vì giá trị giao dịch tối thiểu có thể được giới hạn khác nhau, nên chọn giá trị tối thiểu của hai giá trị này.
3. Các tài sản trên sàn giao dịch bán hoạt động đủ để bán và các tài sản trên sàn giao dịch mua hoạt động đủ để mua.
Khi các điều kiện này được đáp ứng, thực hiện các chức năng bảo hiểm để bảo hiểm. Trước chức năng chính, chúng ta đã tuyên bố một biến trước.isTrade
Để đánh dấu liệu có rủi ro xảy ra hay không, nếu rủi ro được kích hoạt, hãy đặt biến này làtrue
Và đặt lại các biến toàn cầulastKeepBalanceTS
Để 0 (LastKeepBalanceTS được sử dụng để đánh dấu thời gian của hoạt động cân bằng gần đây, đặt vào 0 sẽ kích hoạt hoạt động cân bằng ngay lập tức), sau đó hủy tất cả các danh sách treo.
Hoạt động cân bằng
if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
nowAccs = _C(updateAccs, exchanges)
var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
cancelAll()
if (isBalance) {
lastKeepBalanceTS = ts
if (isTrade) {
var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
isTrade = false
}
}
}
Bạn có thể thấy các hàm cân bằng sẽ được thực hiện thường xuyên, nhưng nếu sau khi kích hoạt các hoạt động đầu cơ, bạn sẽ thấy rằng các hàm cân bằng sẽ được thực hiện thường xuyên, nhưng nếu các hoạt động đầu cơ được kích hoạt sau khi kích hoạt, bạn sẽ thấy rằng các hàm cân bằng sẽ được thực hiện thường xuyên.lastKeepBalanceTS
Việc cân bằng được đặt lại ở 0 sẽ được kích hoạt ngay lập tức. Sau khi cân bằng thành công, lợi nhuận sẽ được tính toán.
Thông tin trạng thái
LogStatus(_D(), "A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, " B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, " targetDiffPrice:", targetDiffPrice, "\n",
"当前A,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n",
"当前B,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n",
"初始A,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n",
"初始B,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
Các thanh trạng thái không có thiết kế phức tạp đặc biệt, hiển thị thời gian hiện tại, hiển thị chênh lệch giữa sàn giao dịch A và sàn giao dịch B và sàn giao dịch B với sàn giao dịch A.
Trong các tham số, chúng tôi đã thiết kế các tham số chuyển đổi giá trị tỷ giá để bắt đầu chiến lược.main
Chúng tôi cũng đã thiết kế chuyển đổi tỷ giá. Điều cần lưu ý làSetRate
Chức năng chuyển đổi tỷ giá cần được thực hiện trước.
Vì hàm này ảnh hưởng đến hai khía cạnh:
BTC_USDT
Các đơn vị giá làUSDT
Các tài sản tài khoản có thể được tính bằng tiền tệUSDT
Nếu tôi muốn chuyển đổi giá trị CNY, hãy đặt trong mã.exchange.SetRate(6.8)
Chỉ cần đặtexchange
Dữ liệu thu được của tất cả các hàm dưới đối tượng này được chuyển đổi thành CNY.
Vì vậy, chúng ta sẽ có một số điều để làm.SetRate
Phương thức truyền tảiGiá trị của đồng tiền hiện tại đối với đồng tiền mục tiêu。Chiến lược đầy đủ:Các chiến lược bảo hiểm hiện tại cho các loại tiền tệ khác nhau
Squirrels là những loài sinh vật có sức sống rộng rãi.Thật tuyệt vời.