
[TOC] В 2020 году я написал статью, посвященную высокочастотным стратегиям: https://www.fmz.com/digest-topic/6228. Хотя эта тема привлекла к себе много внимания, она не была подробно проработана. Прошло более двух лет, и рынок изменился. После публикации этой статьи моя высокочастотная стратегия могла стабильно приносить деньги в течение длительного времени, но прибыль постепенно снижалась и в какой-то момент даже прекратилась. За последние месяцы я потратил много сил на ремонт и теперь могу заработать немного денег. В этой статье я более подробно представлю свои идеи для высокочастотных стратегий и некоторые упрощенные коды, которые могут послужить отправной точкой для обсуждения. Все желающие могут общаться и давать отзывы.
Для аккаунтов, получающих скидки, например, Binance, текущая скидка мейкера составляет 0,5% от 100 000. Если ежедневный объем транзакций составляет 100 миллионов U, скидка составит 5000 U. Конечно, комиссия тейкера по-прежнему основана на ставке VIP, поэтому, если стратегия не требует принятия ордеров, уровень VIP не окажет большого влияния на высокочастотные стратегии. Как правило, разные уровни обмена имеют разные ставки скидок и требуют поддержания более высокого объема транзакций. Давным-давно, когда рынок некоторых валют сильно колебался, прибыль все равно была даже без скидок. С усилением внутреннего оборота, скидки составляли большую долю прибыли, и даже полностью зависели от скидок. Высокочастотные трейдеры преследуют Лучшие цены.
скорость. Причина, по которой высокочастотная стратегия называется высокочастотной, заключается в том, что она очень быстрая. Присоединение к центральному серверу биржи для получения наименьшей задержки и наиболее стабильного соединения также стало одним из условий внутреннего обращения. Внутреннее потребление времени стратегии также должно быть как можно ниже. В этой статье я познакомлю вас с используемым мной фреймворком веб-сокетов, который использует параллельное выполнение.
Правильный рынок. Высокочастотная торговля известна как жемчужина количественной торговли. Я считаю, что многие программные трейдеры пробовали ее, но большинство людей, вероятно, останавливаются, потому что не зарабатывают деньги и не могут найти способ улучшить ее. Главная причина, вероятно, в том, что они ищут неправильный путь. Торговый рынок. На начальном этапе стратегии следует искать относительно легкие рынки для заработка денег, торгуя на них, чтобы была прибыль и обратная связь по улучшениям, что будет способствовать развитию стратегии. Если вы начнете на самом конкурентном рынке и будете конкурировать со многими потенциальными соперниками, вы будете терять деньги, как бы вы ни старались, и не сможете больше удержаться. Я рекомендую новые пары торговли бессрочными контрактами. В настоящее время не так много конкурентов, особенно когда объем торговли относительно большой. Это самое легкое время для заработка. BTC и ETH имеют наибольший объем торгов и самые активные транзакции, но им также сложнее всего выжить.
Встретьтесь с конкурентами лицом к лицу. Любой торговый рынок динамично меняется. Ни одна торговая стратегия не может работать раз и навсегда. Это еще более очевидно в высокочастотной торговле. Выход на этот рынок означает прямую конкуренцию с группой самых умных и усердных трейдеров. На рынке с нулевой суммой чем больше вы зарабатываете, тем меньше зарабатывают другие. Чем позже вы войдете, тем сложнее будет. Те, кто уже на рынке, также должны продолжать совершенствоваться, поскольку они могут быть устранены в любой момент. Три-четыре года назад это должно было быть лучшей возможностью. В последнее время общая активность рынка цифровых валют снизилась, и теперь новичкам очень сложно заниматься высокочастотной торговлей.
Существует много типов высокочастотных стратегий
Моя стратегия — это комбинация тренда и маркет-мейкера. Сначала я определяю тренд, затем размещаю ордер, а после завершения транзакции сразу же размещаю ордер на продажу. Я не держу позиции по инвентарю. Код стратегии представлен ниже.
Следующий код основан на базовой архитектуре бессрочных контрактов Binance и в основном подписывается на рыночную информацию и информацию о позициях потоков ордеров WebSocket. Поскольку рыночная информация и информация о счете подписываются отдельно, необходимо постоянно использовать read(-1), чтобы определить, получена ли последняя информация. EventLoop(1000) используется здесь, чтобы избежать прямого бесконечного цикла и снизить нагрузку на систему. EventLoop(1000) будет заблокирован до тех пор, пока не вернутся wss или параллельные задачи, с тайм-аутом 1000 мс.
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()
}
//需要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是设定的交易对
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)
}
}
Как упоминалось ранее, моя высокочастотная стратегия требует определения тренда перед совершением покупок и продаж. Краткосрочная тенденция в основном оценивается на основе данных о транзакциях по каждой транзакции, то есть aggTrade в подписке, которые включают направление транзакции, цену, количество, время транзакции и т. д. Основными ориентирами при покупке и продаже являются глубина и объем торгов. Далее следует подробное введение в индикаторы, требующие внимания. Большинство индикаторов делятся на две группы: покупка и продажа, и динамически рассчитываются в определенном временном окне. Временное окно моей стратегии находится в пределах 10 секунд.
//bull代表短期看涨,bear短期看跌
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;
Если последняя цена продажи больше средней цены продажи, последняя цена покупки больше средней цены покупки, а фиксированное значение ордера на покупку больше значения ордера на продажу, то это считается краткосрочным бычьим трендом. . Напротив, это медвежий тренд.
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]
}
Здесь мы по-прежнему принимаем старую идею и итерируем глубину до требуемого количества. Здесь мы предполагаем, что ордер на покупку 10 монет может быть выполнен в течение 1 секунды. Без учета новых отложенных ордеров цена ордера на продажу устанавливается в положение, где Ордер на покупку 10 монет будет исполнен. Вам необходимо самостоятельно установить конкретный размер временного окна.
let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time
Соотношение означает фиксированное соотношение, то есть объем ордера на покупку представляет собой фиксированное соотношение объема последнего ордера на продажу. Эта стратегия позволяет адаптивно корректировать размер ордера в зависимости от текущей активности покупок и продаж.
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)
}
Среди них avg_diff — это разница средней рыночной цены. Ордер на покупку будет размещен только тогда, когда спред спроса и предложения больше определенного кратного этого значения, а тренд бычий. Если вы держите короткий ордер, позиция также будет закрыт в это время, чтобы избежать длительного удержания заказа. Вы можете разместить ордер «Только производитель», чтобы гарантировать исполнение отложенного ордера. И вы можете использовать пользовательский идентификатор заказа Binance, поэтому вам не придется ждать возврата заказа.
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 = []
}
/*
需要的任务参数写在param里
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()]})
*/