제가 글을 썼을 때바이낸스 선물 다화폐 헤지 전략에 대한 연구, 나는 또한 백테스트 엔진을 출시했다. 그리고 첫 번째 보고서는 전략의 효과를 검증 한 한 시간 K-라인 백테스트를 기반으로 했다. 그러나 실제 오픈 소스 전략의 수면 시간은 1 초입니다. 이는 상당히 높은 빈도 전략입니다. 분명히, 시간별 K-라인 백테스트를 사용하면 정확한 결과를 얻을 수 없습니다. 나중에, 분 레벨 K 라인의 백테스트의 결과가 추가되었으며, 백테스트 수익은 많이 향상되었지만, 여전히
먼저, 역사적인 K 라인은 무엇입니까? K 라인 데이터는 높은, 개방, 낮은, 닫는, 첫 두
첫 번째는 시간 문제입니다. K-라인 데이터의 가장 높은 가격과 가장 낮은 가격의 시간은 주어지지 않으며 고려할 필요가 없지만 가장 중요한 개출 및 폐쇄 가격은 개출 및 폐쇄 시간이 아닙니다. 덜 인기있는 거래 품종조차도 종종 10 초 이상 거래가 없으며, 다종 다양성 전략을 백테스트 할 때 종종 개출 가격과 폐쇄 가격이 동일하다고 가정합니다. 이는 또한 폐쇄 가격의 백테스트에 기반합니다.
두 종류의 중재를 백테스트하기 위해 분 레벨 K 라인을 사용하는 것을 상상해보십시오. 그 사이의 차이는 일반적으로 10 위안 (또는 달러) 입니다. 이제 10:01에 계약 A의 폐쇄 가격은 100이며 계약 B는 112이며 차이는 12 위안입니다. 따라서 전략은 헤지하기 시작합니다. 특정 순간에 가격 차이는 돌아 왔고 전략은 2 위안의 수익을 얻었습니다.
하지만 실제 상황은 10:00:45에 계약 A가 100 위안의 거래를 생성하고, 그 후에 거래가 없었을 수도 있고, 계약 B가 10:00:58에 112 위안의 거래를 했고, 10:01:00에 두 가격 모두 존재하지 않는다. 현재 시장 가격은 얼마이며, 헤지 운영은 얼마를 얻을 수 있을까? 나는 알 수 없다. 가능한 상황 중 하나는: 10:00:58에 계약 A의 101.9
에102.1
2원 정도의 차이는 전혀 없습니다. 이것은 우리의 전략 최적화를 크게 오해할 것입니다.
두 번째는 매치 메이킹 문제입니다. 실제 매치 메이킹은 가격 우선 순위와 시간 우선 순위입니다. 구매자가
마지막은 시장에 전략 자체의 영향입니다. 작은 금액의 자금의 백테스트라면 영향은 크지 않습니다. 그러나 거래량이 크면 시장에 영향을 미칠 것입니다. 큰 양의 주문을 할 때 가격 미끄러지는 것이 크었을뿐만 아니라, 긴 주문을 실행하는 경우, 이러한 종류의 행동이 실제로 구매하려는 다른 거래자의 주문을 포착합니다. 이 효과는 시장에 영향을 줄 것입니다. 이 효과는 수치화 할 수 없습니다. 우리는 경험으로만 알 수 있습니다. 고주파 거래는 작은 자금을 수용 할 수 있습니다.
FMZ는 실제 수준의 백테스트를 제공합니다.20 layer depth price
, 실시간 두 번째 수준Ticks
, Each Individual Transaction
이러한 특징을 바탕으로 FMZ는 실시간 트랜잭션 재생 기능을 만들었습니다.
이러한 종류의 백테스트 데이터는 매우 크며 백테스트 속도는 매우 느리고 일반적으로 2 일 동안만 백테스트 할 수 있습니다. 상대적으로 높은 주파수 또는 시간적 중요 전략에 대해 실제 시장 수준의 백테스트가 필요합니다. FMZ가 수집한 거래 쌍과 거래 시간은 매우 길지 않지만 여전히 7 억 개 이상의 역사적 데이터가 있습니다.
현재 매치메이크 메커니즘은 구매 주문이
K선에는 너무 적은 정보가 있고, 가격 깊이는 가짜 깊이가 될 수도 있습니다. 하지만 시장의 실제 거래 의지를 나타내는 데이터가 있습니다.Each Individual Transaction
이 기사는 주문 흐름에 기반한 고 빈도 백테스트 시스템을 제안합니다. 이는 실제 시장 수준의 백테스트 데이터의 양을 크게 줄이고 어느 정도 시장에 거래량의 영향을 시뮬레이션합니다.
저는 지난 5일 간 거래의 거래상황을 다운로드했습니다.https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csv), 인기가 없는 품종으로, 총 213000개의 거래 데이터를 가지고 있습니다. 먼저 데이터의 구성에 대해 살펴보겠습니다.
[['XTZ', 1590981301905, 2.905, 0.4, 'False\n'],
['XTZ', 1590981303044, 2.903, 3.6, 'True\n'],
['XTZ', 1590981303309, 2.903, 3.7, 'True\n'],
['XTZ', 1590981303738, 2.903, 238.1, 'True\n'],
['XTZ', 1590981303892, 2.904, 0.1, 'False\n'],
['XTZ', 1590981305250, 2.904, 0.1, 'False\n'],
['XTZ', 1590981305643, 2.903, 197.3, 'True\n'],
데이터 는 시간 순서 로 정렬 된 2 차원 목록 이다. 구체적인 의미 는 다음과 같다: 품종 이름, 거래 가격, 거래 시간표, 거래량, 판매 주문 활성 거래 여부. 구매 및 판매 측면이 있으며, 각 거래에는 구매자와 판매자가 포함됩니다. 구매자가 시장이라면Maker
그리고 판매자는 적극적인Taker
, 마지막 자료는True
.
우선, 거래 방향에 따라 시장에서
주문 흐름에 따라, 그것은 다음과 같이 일치 할 수 있습니다: 예를 들어 구매 주문을 가져, 가격은price
, 주문량은amount
, 다음 구매하고 판매 1 이 시간에bid
그리고ask
각각.price
이보다 낮습니다.ask
이보다 높습니다.bid
, 그 다음에는maker
우선, 우선 순위가 거래에 일치 할 수 있습니다.price
명령어 존재 시간 동안이 명령어와 일치합니다 (만약price
이보다 작거나 같거나bid
, 거래에 우선 순위가 부여되지 않습니다.price
이 순서와 일치합니다.)
일치하는 가격은price
, 그리고 거래량은Each Individual Transaction
, 주문이 완전히 완료되거나 주문이 취소 될 때까지ask
, 그것은taker
그 후, 주문이 존재하는 기간 동안, 거래 가격보다 낮은 또는price
이 주문과 일치합니다. 그리고 일치 가격은Each Individual Transaction
. 그 사이의 차이maker
그리고taker
기본적으로 거래소가 대기 주문을 장려하고 거래 수수료에 대한 할인도 있기 때문입니다.
이런 종류의 매칭에 문제가 있다는 것을 쉽게 알 수 있습니다.taker
, 실제 상황은 즉시 실행 될 수 있다는 것입니다, 새로운 주문을 기다리기 보다는 그것과 일치. 첫째로, 우리는 대기 주문의 양을 고려하지 않습니다, 심지어 일부 데이터가 있지만, 직접 거래도 변화했다 판단 가격 깊이, 시장에 영향을 미치는.
새로운 주문의 매칭을 기반으로, 그것은 역사에 있는 주문을 당신의 주문으로 대체하는 것과 동등합니다. 어떤 경우에도, 그것은 시장의 자체 거래량의 한계를 초과하지 않을 것이며, 최종 이익은 시장에서 생성되는 최대 이익을 초과 할 수 없습니다. 매칭 메커니즘의 일부는 또한 주문의 양에 영향을 미치며, 이는 전략의 수익에 영향을 미치며, 전략의 용량을 양적으로 반영합니다. 자금의 양이 두 배되고 이익이 두 배 될 때 전통적인 백테스트가 없습니다.
아직 몇 가지 작은 세부 사항이 있습니다. 주문의 구매 가격은
교환 객체는 초기에 도입을 참조할 수 있습니다. 기본적으로 변경되지 않습니다.maker
그리고taker
다음에는 주로 매칭 코드를 소개합니다.
symbol = 'XTZ'
loop_time = 0
intervel = 1000 # The sleep time of the strategy is 1000ms
init_price = data[0][2] # Initial price
e = Exchange([symbol],initial_balance=1000000,maker_fee=maker_fee,taker_fee=taker_fee,log='') # Initialize the exchange
depth = {'ask':data[0][2], 'bid':data[0][2]} # depth
order = {'buy':{'price':0,'amount':0,'maker':False,'priority':False,'id':0},
'sell':{'price':0,'amount':0,'maker':False,'priority':False,'id':0}} # order
for tick in data:
price = int(tick[2]/tick_sizes[symbol])*tick_sizes[symbol] # executed price
trade_amount = tick[3] # executed volume
time_stamp = tick[1] # executed timestamp
if tick[4] == 'False\n':
depth['ask'] = price
else:
depth['bid'] = price
if depth['bid'] < order['buy']['price']:
order['buy']['priority'] = True
if depth['ask'] > order['sell']['price']:
order['sell']['priority'] = True
if price > order['buy']['price']:
order['buy']['maker'] = True
if price < order['sell']['price']:
order['sell']['maker'] = True
# Order network delay can also be used as one of the matching conditions, not considered here
cond1 = order['buy']['priority'] and order['buy']['price'] >= price and order['buy']['amount'] > 0
cond2 = not order['buy']['priority'] and order['buy']['price'] > price and order['buy']['amount'] > 0
cond3 = order['sell']['priority'] and order['sell']['price'] <= price and order['sell']['amount'] > 0
cond4 = not order['sell']['priority'] and order['sell']['price'] < price and order['sell']['amount'] > 0
if cond1 or cond2:
buy_price = order['buy']['price'] if order['buy']['maker'] else price
e.Buy(symbol, buy_price, min(order['buy']['amount'],trade_amount), order['buy']['id'], order['buy']['maker'])
order['buy']['amount'] -= min(order['buy']['amount'],trade_amount)
e.Update(time_stamp,[symbol],{symbol:price})
if cond3 or cond4:
sell_price = order['sell']['price'] if order['sell']['maker'] else price
e.Sell(symbol, sell_price, min(order['sell']['amount'],trade_amount), order['sell']['id'], order['sell']['maker'])
order['sell']['amount'] -= min(order['sell']['amount'],trade_amount)
e.Update(time_stamp,[symbol],{symbol:price})
if time_stamp - loop_time > intervel:
order = get_order(e,depth,order) # Trading logic, not given here
loop_time += int((time_stamp - loop_time)/intervel)*intervel
몇 가지 세부 사항:
새로운 거래가 있을 때, 먼저 주문을 맞추고, 그 다음 최신 가격에 따라 주문을 해야 합니다.
각 주문은 두 가지 속성을 가지고 있습니다: 메이커maker
, 구매가격이 Priority matching
, priority
가격이 구매 가격과 같는지 아닌지를 결정하고, 메이커는 거래 수수료를 결정합니다.
이maker
그리고priority
주문의 크기가 큰 경우 시장 용량을 초과합니다. 가격이 구매 가격보다 높을 때, 나머지 부피는maker
.
전략interval
필요한 경우, 시장의 지연을 나타낼 수 있습니다.
마지막으로, 그것은 실제 백테스트 단계입니다. 우리가 예상 결과를 달성 할 수 있는지 확인하기 위해 가장 고전적인 그리드 전략 중 하나를 백테스트 해 봅시다. 전략의 원리는 가격이 1% 상승 할 때마다 특정 가치의 짧은 주문을 보유한다는 것입니다 (반대의 경우, 우리는 긴 주문을 보유하고 있습니다), 사전에 구매 주문과 판매 주문을 계산합니다.Grid('XTZ', 100, 0.3, 1000, maker_fee=-0.00002, taker_fee=0.0003)
함수, 매개 변수는: 거래 쌍, 가격 보유 가치에서 1%의 오차, 대기 주문 밀도는 0.3%입니다, 수면 간격ms
, 미결 주문 수수료 및 실행 주문 수수료.
지난 5일 동안 XTZ
먼저 우리는 수익 수익에 대한 다른 보유 지점의 영향을 백테스트합니다. 전통적인 백테스트 메커니즘으로 백테스트 된 수익은 보유 지점의 증가에 비례하여 확실히 증가합니다.
e1 = Grid('XTZ',100,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e1.account['USDT'])
e2 = Grid('XTZ',1000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e2.account['USDT'])
e3 = Grid('XTZ',10000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e3.account['USDT'])
e4 = Grid('XTZ',100000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e4.account['USDT'])
총 4개의 그룹에 백테스트가 실시되었으며, 보유 포지션의 값은 100, 1000, 10000, 100,000이며, 총 백테스트 시간은 1.3초였습니다. 결과는 다음과 같습니다.
{'realised_profit': 28.470993031132966, 'margin': 0.7982662957624465, 'unrealised_profit': 0.0104554474048441, 'total': 10000028.481448, 'leverage': 0.0, 'fee': -0.3430967859046398, 'maker_fee': -0.36980249726699727, 'taker_fee': 0.026705711362357405}
{'realised_profit': 275.63148945320177, 'margin': 14.346335829979132, 'unrealised_profit': 4.4382117331794045e-14, 'total': 10000275.631489, 'leverage': 0.0, 'fee': -3.3102045933457784, 'maker_fee': -3.5800688964477048, 'taker_fee': 0.2698643031019274}
{'realised_profit': 2693.8701498889504, 'margin': 67.70120400534114, 'unrealised_profit': 0.5735269329348516, 'total': 10002694.443677, 'leverage': 0.0001, 'fee': -33.984021415250744, 'maker_fee': -34.879233866850974, 'taker_fee': 0.8952124516001403}
{'realised_profit': 22610.231198585603, 'margin': 983.3853688758861, 'unrealised_profit': -20.529965947304365, 'total': 10022589.701233, 'leverage': 0.002, 'fee': -200.87094000385412, 'maker_fee': -261.5849078470078, 'taker_fee': 60.71396784315319}
최종 실현 이익은 보유 지점 가치의 각각 28.4%, 27.5%, 26.9% 및 22.6%로 볼 수 있습니다. 이것은 또한 실제 상황과 일치합니다. 보유 지점 가치가 높을수록 미뤄진 주문의 가치가 높을수록 부분 거래가 발생할 가능성이 높고 미뤄진 주문 금액에 비해 최종 실현 이익이 작을 수 있습니다. 다음 차트는 각각 100 및 10000의 위치 가치의 상대적 수익률을 비교합니다.
우리는 또한 대기 주문 밀도, 잠자리 시간, 거래 수수료 등과 같은 백테스트 수익에 대한 다른 매개 변수의 영향을 백테스트 할 수 있습니다. 예를 들어 잠자리 시간을 100ms로 변경하고 수익 수익을 보기 위해 잠자리 시간을 1000ms로 비교하십시오. 백테스트 결과는 다음과 같습니다.
{'realised_profit': 29.079440803790423, 'margin': 0.7982662957624695, 'unrealised_profit': 0.0104554474048441, 'total': 10000029.089896, 'leverage': 0.0, 'fee': -0.3703702128662524, 'maker_fee': -0.37938946377435134, 'taker_fee': 0.009019250908098965}
수익은 약간 증가했습니다. 전략은 단지 일련의 주문을 보내기 때문에, 일부 주문은 변경할 시간이 없기 때문에 변동 가격을 실행할 수 없습니다. 그리고 수면 시간의 감소는이 문제를 개선합니다. 이것은 또한 여러 세트의 주문을 배치하기위한 그리드 전략의 중요성을 보여줍니다.
이 문서에서는 주문 흐름에 기반한 새로운 백테스트 시스템을 혁신적으로 제안하고 있으며, 이는 대기 중인 주문, 실행 중인 주문, 일부 실행된 주문, 지연 등의 일치 상황을 부분적으로 시뮬레이션 할 수 있으며, 전략 자금액의 수익에 미치는 영향을 부분적으로 반영합니다. 고주파 및 헤지 전략에 대해서는 중요한 참조 가치를 가지고 있습니다. 고정도 백테스트는 전략 매개 변수 최적화의 방향을 나타냅니다. 또한 오랫동안 검증되었습니다. 게다가 백테스트에 필요한 데이터의 양은 잘 제어되며 백테스트 속도는 또한 매우 빠릅니다.