Saya menulis artikel pada tahun 2020 memperkenalkan strategi perdagangan frekuensi tinggi (https://www.fmz.com/digest-topic/6228Walaupun ia mendapat perhatian, ia tidak sangat mendalam. Dua setengah tahun telah berlalu sejak itu, dan pasaran telah berubah. Selepas saya menerbitkan artikel itu, strategi frekuensi tinggi saya dapat membuat keuntungan yang stabil untuk masa yang lama, tetapi keuntungan secara beransur-ansur menurun dan bahkan berhenti pada satu ketika. Dalam beberapa bulan kebelakangan ini, saya telah meluangkan masa untuk memperbaharui, dan ia masih boleh menghasilkan beberapa keuntungan kecil.
Akaun diskaun Suruhanjaya
menggunakan Binance sebagai contoh, kini menawarkan potongan harga pembuat sebanyak 0.05% untuk setiap 100,000 unit yang didagangkan. Jika jumlah dagangan harian adalah 100 juta U, potongan harga adalah 5,000 U. Sudah tentu, yuran penerima masih bergantung pada kadar VIP, jadi jika strategi tidak perlu mengambil pesanan, tahap VIP mempunyai sedikit kesan pada strategi frekuensi tinggi. Pelbagai tahap potongan harga komisen tersedia di bursa yang berbeza, yang memerlukan jumlah dagangan yang tinggi. Pada hari-hari awal, masih ada keuntungan yang boleh dibuat tanpa potongan harga, tetapi ketika persaingan semakin sengit, potongan harga menyumbang sebahagian besar keuntungan, dan pedagang frekuensi tinggi mengejar kadar teratas.
Kelajuan
Perdagangan frekuensi tinggi dipanggil demikian kerana kelajuannya yang cepat. Bergabung dengan pelayan colocation bursa perdagangan dan mendapatkan latensi terendah dan sambungan paling stabil telah menjadi salah satu syarat persaingan. Waktu pemprosesan dalaman strategi juga harus serendah mungkin. Artikel ini akan memperkenalkan kerangka WebSocket yang saya gunakan, yang menggunakan pelaksanaan serentak.
Pasaran yang sesuai
Perdagangan frekuensi tinggi dianggap sebagai permata dalam mahkota perdagangan kuantitatif, dan saya percaya bahawa banyak peniaga algoritma telah mencubanya, tetapi kebanyakan orang seharusnya berhenti kerana mereka tidak dapat membuat wang dan tidak dapat mencari cara untuk meningkatkan. Sebab utama mungkin kerana mereka memilih pasaran perdagangan yang salah. Pada peringkat awal strategi, pasaran yang agak mudah harus disasarkan untuk berdagang untuk memperoleh keuntungan dan menerima maklum balas untuk peningkatan, yang kondusif untuk kemajuan strategi. Jika anda memulakan di pasaran yang paling kompetitif dan bersaing dengan banyak lawan, anda akan kehilangan wang tidak kira seberapa keras anda mencuba, dan anda akan segera menyerah. Saya mengesyorkan memulakan dengan pasangan perdagangan kontrak kekal yang baru dilancarkan, di mana terdapat lebih sedikit pesaing, terutama yang mempunyai jumlah perdagangan yang agak besar, menjadikannya lebih mudah untuk membuat wang. BTC dan ETH mempunyai jumlah perdagangan yang paling tinggi dan paling aktif, tetapi mereka juga paling sukar untuk bertahan.
Menghadapi persaingan secara langsung
Pasaran untuk mana-mana perdagangan sentiasa berubah, dan tidak ada strategi perdagangan yang boleh menjadi penyelesaian satu kali. Ini lebih jelas dalam perdagangan frekuensi tinggi, di mana memasuki pasaran bermakna bersaing secara langsung dengan peniaga yang paling pintar dan paling rajin. Dalam pasaran permainan jumlah sifar, semakin banyak yang anda peroleh, semakin sedikit yang lain memperoleh. Semakin lambat anda memasuki, semakin sukar, dan mereka yang sudah berada di pasaran mesti sentiasa bertambah baik dan boleh dihapuskan pada bila-bila masa. Tiga atau empat tahun yang lalu mungkin merupakan peluang terbaik, tetapi dengan penurunan keseluruhan aktiviti di pasaran mata wang digital baru-baru ini, menjadi sangat sukar bagi pemula untuk memulakan perdagangan frekuensi tinggi.
Terdapat beberapa strategi perdagangan frekuensi tinggi, seperti arbitraj frekuensi tinggi, yang melibatkan mencari peluang arbitraj melalui bursa ini atau yang lain, merebut peluang untuk memakan pesanan sebelum yang lain dan membuat keuntungan dengan kelebihan kelajuan; perdagangan trend frekuensi tinggi, yang melibatkan keuntungan dari trend jangka pendek; dan pembuatan pasaran, yang melibatkan penempatan pesanan di kedua-dua belah pihak perdagangan beli dan jual, mengawal kedudukan dengan baik dan memperoleh keuntungan melalui potongan komisen. Strategi saya menggabungkan trend dan pembuatan pasaran, pertama mengenal pasti trend dan kemudian meletakkan pesanan, menjual segera selepas pelaksanaan dan tidak memegang kedudukan inventori. Di bawah ini adalah pengenalan kepada kod strategi.
Kod berikut adalah berdasarkan seni bina asas kontrak kekal Binance dan terutamanya melanggan perdagangan aliran pesanan kedalaman websocket dan maklumat kedudukan. Oleh kerana data pasaran dan maklumat akaun dilabel secara berasingan, membaca (-1) perlu digunakan secara berterusan untuk menentukan sama ada maklumat terkini telah diperoleh. Di sini, EventLoop (1000) digunakan untuk mengelakkan gelung mati langsung dan mengurangkan beban sistem. EventLoop (1000) menyekat sehingga terdapat wss atau kembalinya tugas serentak, dengan masa lapang 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)
}
}
Seperti yang disebutkan sebelumnya, strategi frekuensi tinggi saya memerlukan trend yang pertama dikenal pasti sebelum menjalankan perdagangan beli dan jual. Penghakiman trend jangka pendek terutamanya berdasarkan data transaksi, iaitu, aggTrade yang ditaja, yang merangkumi arah, harga, kuantiti, dan masa transaksi. Perdagangan beli dan jual terutamanya merujuk kepada kedalaman dan jumlah transaksi. Berikut adalah penunjuk terperinci yang perlu dipertimbangkan, yang kebanyakannya dibahagikan kepada dua kumpulan untuk membeli dan menjual dan dikira secara dinamik dalam jangka masa tertentu. Jendela masa strategi saya adalah dalam 10 saat.
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;
Jika harga beli terakhir lebih besar daripada harga jual purata dan harga tawaran terakhir lebih besar daripada harga tawaran purata dan nilai pesanan beli lebih besar daripada nilai pesanan jual pada selang masa yang tetap, maka ia dinilai sebagai pasaran bullish jangka pendek.
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]
}
Di sini, kaedah lama untuk mengulangi kedalaman kepada kuantiti yang diperlukan masih digunakan. Dengan mengandaikan bahawa pesanan beli yang boleh dilaksanakan untuk 10 syiling dalam masa 1 saat dan tanpa mempertimbangkan keadaan pesanan baru, harga jual ditetapkan pada kedudukan di mana pesanan beli
dengan jumlah 10 syiling boleh memukul. saiz tetingkap masa tertentu perlu ditetapkan oleh diri sendiri.
let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time
Nisbah ini mewakili perkadaran tetap kuantiti pesanan jual terakhir, mewakili kuantiti pesanan beli sebagai perkadaran tetap kuantiti pesanan jual terakhir. Ini membolehkan strategi untuk menyesuaikan saiz pesanan mengikut aktiviti pembelian dan penjualan semasa.
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)
}
Antara mereka, avg_diff adalah perbezaan purata dalam penyebaran, dan hanya apabila perbezaan beli dan jual dalam meletakkan pesanan lebih besar daripada kelipatan tertentu dari nilai ini dan pasaran bullish, pesanan beli akan diletakkan. Jika memegang kedudukan pendek, kedudukan juga akan ditutup untuk mengelakkan memegang kedudukan untuk masa yang lama. Perintah pembuat sahaja boleh diletakkan untuk memastikan pesanan dipenuhi, dan ID pesanan tersuai boleh digunakan untuk mengelakkan menunggu pulangan pesanan.
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()]})
*/