Tôi đã viết một bài báo vào năm 2020 giới thiệu các chiến lược giao dịch tần số cao (https://www.fmz.com/digest-topic/6228) Mặc dù nó nhận được một số sự chú ý, nhưng nó không phải là rất sâu sắc. Hai năm rưỡi đã trôi qua kể từ đó, và thị trường đã thay đổi. Sau khi tôi xuất bản bài viết đó, chiến lược tần số cao của tôi đã có thể kiếm được lợi nhuận ổn định trong một thời gian dài, nhưng lợi nhuận dần dần giảm và thậm chí dừng lại ở một thời điểm. Trong những tháng gần đây, tôi đã dành thời gian để cải thiện nó, và nó vẫn có thể kiếm được một số lợi nhuận nhỏ. Bài viết này sẽ cung cấp một giới thiệu chi tiết hơn về chiến lược giao dịch tần số cao của tôi và một số mã đơn giản, phục vụ như một điểm khởi đầu cho thảo luận và phản hồi.
Tài khoản giảm giá của Ủy ban
sử dụng Binance làm ví dụ, hiện đang cung cấp giảm giá nhà sản xuất 0,05% cho mỗi 100.000 đơn vị giao dịch. Nếu khối lượng giao dịch hàng ngày là 100 triệu U, giảm giá là 5.000 U. Tất nhiên, phí người nhận vẫn phụ thuộc vào tỷ lệ VIP, vì vậy nếu chiến lược không cần phải nhận lệnh, mức VIP có ít ảnh hưởng đến chiến lược tần suất cao. Các mức giảm giá hoa hồng khác nhau có sẵn trên các sàn giao dịch khác nhau, đòi hỏi khối lượng giao dịch cao. Trong những ngày đầu, vẫn có lợi nhuận mà không cần giảm giá, nhưng khi cạnh tranh gia tăng, giảm giá chiếm tỷ lệ lợi nhuận lớn hơn và các nhà giao dịch tần suất cao theo đuổi tỷ lệ cao nhất.
Tốc độ
Giao dịch tần số cao được gọi là giao dịch tần số cao vì tốc độ nhanh. Tham gia máy chủ colocation của sàn giao dịch và có được độ trễ thấp nhất và kết nối ổn định nhất đã trở thành một trong những điều kiện cạnh tranh. Thời gian xử lý nội bộ của chiến lược cũng nên thấp nhất có thể. Bài viết này sẽ giới thiệu khung WebSocket mà tôi đã sử dụng, sử dụng thực thi đồng thời.
Thị trường thích hợp
Thương mại tần số cao được coi là viên ngọc trong vương miện của giao dịch định lượng, và tôi tin rằng nhiều nhà giao dịch thuật toán đã thử nó, nhưng hầu hết mọi người nên dừng lại vì họ không thể kiếm tiền và không thể tìm ra cách để cải thiện. Lý do chính có lẽ là vì họ đã chọn sai thị trường giao dịch. Trong giai đoạn ban đầu của chiến lược, các thị trường tương đối dễ dàng nên được nhắm mục tiêu giao dịch để kiếm lợi nhuận và nhận phản hồi để cải thiện, điều này có lợi cho sự tiến bộ của chiến lược. Nếu bạn bắt đầu trong thị trường cạnh tranh khốc liệt nhất và cạnh tranh với nhiều đối thủ, bạn sẽ mất tiền bất kể bạn cố gắng khó khăn thế nào, và bạn sẽ nhanh chóng bỏ cuộc. Tôi khuyên bạn nên bắt đầu với các cặp giao dịch hợp đồng vĩnh cửu mới ra mắt, nơi có ít đối thủ cạnh tranh hơn, đặc biệt là những đối thủ có khối lượng giao dịch tương đối lớn, làm cho việc kiếm tiền dễ dàng hơn. BTC và ETH có khối lượng giao dịch cao nhất và hoạt động nhiều nhất, nhưng chúng cũng khó tồn tại nhiều nhất.
Đối mặt với đối thủ trực tiếp
Thị trường cho bất kỳ giao dịch nào đều liên tục thay đổi, và không có chiến lược giao dịch nào có thể là giải pháp một lần. Điều này thậm chí còn rõ ràng hơn trong giao dịch tần số cao, nơi nhập thị trường có nghĩa là cạnh tranh trực tiếp với các nhà giao dịch thông minh và siêng năng nhất. Trong thị trường trò chơi tổng bằng không, bạn càng kiếm được nhiều, người khác càng kiếm được ít. Bạn càng đi vào muộn, càng khó khăn, và những người đã có mặt trên thị trường phải liên tục cải thiện và có thể bị loại bỏ bất cứ lúc nào. Ba hoặc bốn năm trước đây có lẽ là cơ hội tốt nhất, nhưng với sự suy giảm tổng thể gần đây trong hoạt động trên thị trường tiền kỹ thuật số, việc bắt đầu giao dịch tần số cao đã trở nên rất khó khăn cho người mới bắt đầu.
Có một số chiến lược giao dịch tần số cao, chẳng hạn như chênh lệch tần số cao, liên quan đến việc tìm kiếm các cơ hội chênh lệch thông qua giao dịch này hoặc các sàn giao dịch khác, nắm bắt cơ hội ăn các đơn đặt hàng trước những người khác và kiếm lợi nhuận với lợi thế tốc độ; giao dịch xu hướng tần số cao, liên quan đến việc kiếm lợi từ các xu hướng ngắn hạn; và tạo thị trường, liên quan đến việc đặt đơn đặt hàng ở cả hai bên của giao dịch mua và bán, kiểm soát các vị trí tốt và kiếm lợi nhuận thông qua giảm giá hoa hồng.
Mã sau dựa trên kiến trúc cơ bản của hợp đồng vĩnh cửu Binance và chủ yếu đăng ký giao dịch luồng lệnh chiều sâu websocket và thông tin vị trí. Vì dữ liệu thị trường và thông tin tài khoản được đăng ký riêng biệt, cần phải đọc (-1) liên tục để xác định liệu thông tin mới nhất đã được thu thập hay không. Ở đây, EventLoop (1000) được sử dụng để tránh các vòng chết trực tiếp và giảm tải hệ thống. EventLoop (1000) chặn cho đến khi có một wss hoặc trả về nhiệm vụ đồng thời, với thời gian hết 1000ms.
var datastream = null
var tickerstream = null
var update_listenKey_time = 0
function ConncetWss(){
if (Date.now() - update_listenKey_time < 50*60*1000) {
return
}
if(datastream || tickerstream){
datastream.close()
tickerstream.close()
}
// need APIKEY
let req = HttpQuery(Base+'/fapi/v1/listenKey', {method: 'POST',data: ''}, null, 'X-MBX-APIKEY:' + APIKEY)
let listenKey = JSON.parse(req).listenKey
datastream = Dial("wss://fstream.binance.com/ws/" + listenKey + '|reconnect=true', 60)
// Symbols is the pair of symbol
let trade_symbols_string = Symbols.toLowerCase().split(',')
let wss_url = "wss://fstream.binance.com/stream?streams="+trade_symbols_string.join(Quote.toLowerCase()+"@aggTrade/")+Quote.toLowerCase()+"@aggTrade/"+trade_symbols_string.join(Quote.toLowerCase()+"@depth20@100ms/")+Quote.toLowerCase()+"@depth20@100ms"
tickerstream = Dial(wss_url+"|reconnect=true", 60)
update_listenKey_time = Date.now()
}
function ReadWss(){
let data = datastream.read(-1)
let ticker = tickerstream.read(-1)
while(data){
data = JSON.parse(data)
if (data.e == 'ACCOUNT_UPDATE') {
updateWsPosition(data)
}
if (data.e == 'ORDER_TRADE_UPDATE'){
updateWsOrder(data)
}
data = datastream.read(-1)
}
while(ticker){
ticker = JSON.parse(ticker).data
if(ticker.e == 'aggTrade'){
updateWsTrades(ticker)
}
if(ticker.e == 'depthUpdate'){
updateWsDepth(ticker)
}
ticker = tickerstream.read(-1)
}
makerOrder()
}
function main() {
while(true){
ConncetWss()
ReadWss()
worker()
updateStatus()
EventLoop(1000)
}
}
Như đã đề cập trước đây, chiến lược tần số cao của tôi đòi hỏi phải xác định xu hướng trước khi thực hiện giao dịch mua và bán. Đánh giá xu hướng ngắn hạn chủ yếu dựa trên dữ liệu giao dịch, tức là, aggTrade đã đăng ký, bao gồm hướng, giá, số lượng và thời gian giao dịch. Các giao dịch mua và bán chủ yếu đề cập đến độ sâu và khối lượng giao dịch. Sau đây là các chỉ số chi tiết cần được xem xét, hầu hết trong số đó được chia thành hai nhóm để mua và bán và được tính năng động trong một cửa sổ thời gian nhất định.
let bull = last_sell_price > avg_sell_price && last_buy_price > avg_buy_price &&
avg_buy_amount / avg_buy_time > avg_sell_amount / avg_sell_time;
let bear = last_sell_price < avg_sell_price && last_buy_price < avg_buy_price &&
avg_buy_amount / avg_buy_time < avg_sell_amount / avg_sell_time;
Nếu giá mua cuối cùng lớn hơn giá mua trung bình và giá mua cuối cùng lớn hơn giá mua trung bình và giá trị lệnh mua lớn hơn giá trị lệnh bán ở một khoảng thời gian cố định, thì nó được đánh giá là một thị trường tăng ngắn hạn. Điều ngược lại đúng với các thị trường giảm.
function updatePrice(depth, bid_amount, ask_amount) {
let buy_price = 0
let sell_price = 0
let acc_bid_amount = 0
let acc_ask_amount = 0
for (let i = 0; i < Math.min(depth.asks.length, depth.bids.length); i++) {
acc_bid_amount += parseFloat(depth.bids[i][1])
acc_ask_amount += parseFloat(depth.asks[i][1])
if (acc_bid_amount > bid_amount && buy_price == 0) {
buy_price = parseFloat(depth.bids[i][0]) + tick_size
}
if (acc_ask_amount > ask_amount && sell_price == 0) {
sell_price = parseFloat(depth.asks[i][0]) - tick_size
}
if (buy_price > 0 && sell_price > 0) {
break
}
}
return [buy_price, sell_price]
}
Ở đây, phương pháp cũ của lặp lại chiều sâu đến số lượng cần thiết vẫn được sử dụng. Giả sử rằng một lệnh mua có thể được thực hiện cho 10 đồng xu trong vòng 1 giây và mà không xem xét tình hình của các lệnh mới, giá bán được thiết lập ở vị trí mà lệnh mua
với một khối lượng 10 đồng xu có thể đánh. kích thước cửa sổ thời gian cụ thể cần phải được thiết lập bởi chính mình.
let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time
Tỷ lệ này đại diện cho một tỷ lệ cố định của số lượng đơn đặt hàng bán gần nhất, đại diện cho số lượng đơn đặt hàng mua như một tỷ lệ cố định của số lượng đơn đặt hàng bán gần nhất. Điều này cho phép chiến lược điều chỉnh kích thước đơn đặt hàng theo hoạt động mua và bán hiện tại.
if(bull && (sell_price-buy_price) > N * avg_diff) {
trade('buy', buy_price, buy_amount)
}else if(position.amount < 0){
trade('buy', buy_price, -position.amount)
}
if(bear && (sell_price-buy_price) > N * avg_diff) {
trade('sell', sell_price, sell_amount)
}else if(position.amount > 0){
trade('sell', sell_price, position.amount)
}
Trong số đó, avg_diff là chênh lệch trung bình trong chênh lệch, và chỉ khi chênh lệch mua và bán trong đặt lệnh lớn hơn một số lần số này và thị trường tăng sẽ đặt lệnh mua. Nếu giữ một vị trí ngắn, vị trí cũng sẽ được đóng để tránh giữ vị trí trong một thời gian dài. Chỉ có thể đặt đơn đặt hàng để đảm bảo rằng các đơn đặt hàng được hoàn thành, và ID đơn đặt hàng tùy chỉnh có thể được sử dụng để tránh chờ đợi các đơn đặt hàng trở lại.
var tasks = []
var jobs = []
function worker(){
let new_jobs = []
for(let i=0; i<tasks.length; i++){
let task = tasks[i]
jobs.push(exchange.Go.apply(this, task.param))
}
_.each(jobs, function(t){
let ret = t.wait(-1)
if(ret === undefined){
new_jobs.push(t)//未返回的任务下次继续等待
}
})
jobs = new_jobs
tasks = []
}
/*
tasks.push({'type':'order','param': ["IO", "api", "POST","/fapi/v1/order",
"symbol="+symbol+Quote+"&side="+side+"&type=LIMIT&timeInForce=GTX&quantity="+
amount+"&price="+price+"&newClientOrderId=" + UUID() +"×tamp="+Date.now()]})
*/