영구적 격자 전략은 플랫폼에서 매우 인기있는 고전적인 전략이다. 현장 격자보다 현장 격자보다 지폐를 사용하지 않고 활용이 가능하며 현장 격자보다 훨씬 편리하다. 그러나 발명자의 플랫폼에서 직접 재검토를 정량화 할 수 없기 때문에 통화 종류를 필터링하고 매개 변수 최적화를 결정하는 것이 좋지 않기 때문에 이 문서에서는 데이터 수집, 재검토 프레임워크 재검토, 측정 함수, 매개 변수 최적화 등 모든 측면을 포함하는 완전한 파이썬 재검토 프로세스를 소개합니다.
일반적으로 K선 데이터로 충분하다. 정확성을 위해, K선 주기가 작을수록 더 좋지만, 재검토 시간과 데이터 양을 균형을 맞추고, 이 문서에서는 5min을 사용하여 최근 2 년의 데이터를 재검토하여 최종 데이터 양이 20W 라인을 초과했으며, 통화는 DYDX를 선택했습니다. 물론 특정 통화와 K선 주기는 자신의 관심사에 따라 선택할 수 있습니다.
import requests
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests, zipfile, io
%matplotlib inline
def GetKlines(symbol='BTC',start='2020-8-10',end='2021-8-10',period='1h'):
Klines = []
start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))*1000
end_time = int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000
while start_time < end_time:
res = requests.get('https://fapi.binance.com/fapi/v1/klines?symbol=%sUSDT&interval=%s&startTime=%s&limit=1000'%(symbol,period,start_time))
res_list = res.json()
Klines += res_list
start_time = res_list[-1][0]
return pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')
df = GetKlines(symbol='DYDX',start='2022-1-1',end='2023-12-7',period='5m')
df = df.drop_duplicates()
재검토는 기존에 널리 사용되었던 USDT를 지원하는 영구 계약 다화폐 프레임워크를 계속 선택하여 간단하게 사용할 수 있습니다.
class Exchange:
def __init__(self, trade_symbols, fee=0.0004, initial_balance=10000):
self.initial_balance = initial_balance #初始的资产
self.fee = fee
self.trade_symbols = trade_symbols
self.account = {'USDT':{'realised_profit':0, 'unrealised_profit':0, 'total':initial_balance, 'fee':0}}
for symbol in trade_symbols:
self.account[symbol] = {'amount':0, 'hold_price':0, 'value':0, 'price':0, 'realised_profit':0,'unrealised_profit':0,'fee':0}
def Trade(self, symbol, direction, price, amount):
cover_amount = 0 if direction*self.account[symbol]['amount'] >=0 else min(abs(self.account[symbol]['amount']), amount)
open_amount = amount - cover_amount
self.account['USDT']['realised_profit'] -= price*amount*self.fee #扣除手续费
self.account['USDT']['fee'] += price*amount*self.fee
self.account[symbol]['fee'] += price*amount*self.fee
if cover_amount > 0: #先平仓
self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount #利润
self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount
self.account[symbol]['amount'] -= -direction*cover_amount
self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price']
if open_amount > 0:
total_cost = self.account[symbol]['hold_price']*direction*self.account[symbol]['amount'] + price*open_amount
total_amount = direction*self.account[symbol]['amount']+open_amount
self.account[symbol]['hold_price'] = total_cost/total_amount
self.account[symbol]['amount'] += direction*open_amount
def Buy(self, symbol, price, amount):
self.Trade(symbol, 1, price, amount)
def Sell(self, symbol, price, amount):
self.Trade(symbol, -1, price, amount)
def Update(self, close_price): #对资产进行更新
self.account['USDT']['unrealised_profit'] = 0
for symbol in self.trade_symbols:
self.account[symbol]['unrealised_profit'] = (close_price[symbol] - self.account[symbol]['hold_price'])*self.account[symbol]['amount']
self.account[symbol]['price'] = close_price[symbol]
self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*close_price[symbol]
self.account['USDT']['unrealised_profit'] += self.account[symbol]['unrealised_profit']
self.account['USDT']['total'] = round(self.account['USDT']['realised_profit'] + self.initial_balance + self.account['USDT']['unrealised_profit'],6)
네트워크 전략의 원리는 매우 간단합니다. 판매가 증가하고 구매가 감소합니다. 세 가지 매개 변수와 관련이 있습니다: 초기 가격, 네트워크 간격, 거래 가치. DYDX의 시장 변동은 매우 크며 초기 8.6U 최저에서 1U 이상 떨어졌습니다. 최근 쇠시장은 다시 3U로 돌아갔습니다. 전략의 기본 초기 가격은 8.6U입니다. 이것은 네트워크 전략에 매우 불리합니다.
symbol = 'DYDX'
value = 100
pct = 0.01
def Grid(fee=0.0002, value=100, pct=0.01, init = df.close[0]):
e = Exchange([symbol], fee=0.0002, initial_balance=10000)
init_price = init
res_list = [] #用于储存中间结果
for row in df.iterrows():
kline = row[1] #这样会测一根K线只会产生一个买单或一个卖单,不是特别精确
buy_price = (value / pct - value) / ((value / pct) / init_price + e.account[symbol]['amount']) #买单价格,由于是挂单成交,也是最终的撮合价格
sell_price = (value / pct + value) / ((value / pct) / init_price + e.account[symbol]['amount'])
if kline.low < buy_price: #K线最低价低于当前挂单价,买单成交
e.Buy(symbol,buy_price,value/buy_price)
if kline.high > sell_price:
e.Sell(symbol,sell_price,value/sell_price)
e.Update({symbol:kline.close})
res_list.append([kline.time, kline.close, e.account[symbol]['amount'], e.account['USDT']['total']-e.initial_balance,e.account['USDT']['fee'] ])
res = pd.DataFrame(data=res_list, columns=['time','price','amount','profit', 'fee'])
res.index = pd.to_datetime(res.time,unit='ms')
return res
초기 가격의 설정은 전략의 초기 보유에 영향을 미치며, 방금 재검토된 기본 초기 가격은 시작시의 초기 가격, 즉 시작시의 보유가 없다. 그리고 우리는 네트워크 전략이 가격의 초기 반환에 모든 이익을 벌어들일 것이라는 것을 알고 있기 때문에 전략의 시작시에는 미래에 대한 올바른 예측이 가능하다면 수익이 크게 증가 할 것입니다. 여기서 초기 가격을 3U로 설정하여 다시 재검토하십시오. 최종 최대 회수 9200U, 최종 수익 13372U. 최종 전략은 보유하지 않습니다. 이 수익은 모든 변동 수익이며 기본 매개 변수에서 수익과 차이가있는 부분은 최종 가격 판단에 대한 보유 손실을 허용하지 않는다는 것입니다.
그러나 초기 가격은 3U로 설정되어 있으며, 전략은 초기에는 빈 채로 많은 빈 채를 보유하게 될 것이며, 이 경우 17,000U의 빈 채권을 직접 보유하고 있으므로 더 큰 위험에 직면합니다.
격자 간격은 종목의 거리를 결정하는데, 분명히 격자 간격이 작을수록 거래가 빈번해지고, 단편의 이익이 낮을수록 절차 수수료도 높습니다. 그러나 주목할 점은 격자 간격이 작아지고, 격자 가치는 변하지 않으며, 가격이 변할 때 총 보유량이 증가하고, 직면한 위험은 완전히 다릅니다. 따라서 격자 간격의 역할을 재검토하려면 격자 가치를 환산해야합니다.
리테이팅은 5mK 라인 데이터로 이루어지고 K 라인에서 한 번만 거래되기 때문에;; 이것은 분명히 현실과 일치하지 않습니다. 특히 디지털 화폐의 변동률이 매우 높고, 작은 간격은 리테이팅에서 실제와 비교하여 많은 거래를 놓칠 수 있으므로, 더 큰 간격만 참조 가치가 있습니다. 이러한 리테이팅 메커니즘에서 결론은 정확하지 않습니다. 틱 레벨 주문 흐름 데이터 리테이팅을 통해 최적의 격자 간격은 0.005-0.01이어야합니다.
for p in [0.0005, 0.001 ,0.002 ,0.005, 0.01, 0.02, 0.05]:
res = Grid( fee=0.0002, value=value*p/0.01, pct=p, init =3)
print(p, round(min(res['profit']),0), round(res['profit'][-1],0), round(res['fee'][-1],0))
0.0005 -8378.0 144.0 237.0
0.001 -9323.0 1031.0 465.0
0.002 -9306.0 3606.0 738.0
0.005 -9267.0 9457.0 781.0
0.01 -9228.0 13375.0 550.0
0.02 -9183.0 15212.0 309.0
0.05 -9037.0 16263.0 131.0
앞서 언급한 바와 같이, 변동이 동시에 있을 때, 보유한 가치는 더 커지고, 위험 등 비율적인 방법이지만 급격한 하락이 아니라면, 전체 자본의 1%와 1%의 격자 간격은 대부분의 시장을 감당해야 한다. 이 경우 DYDX의 경우, 거의 90%의 하락이 폭발 시장을 유발한다. 그러나 DYDX가 주로 하락하고, 하락할 때 격자 전략이 더 많이, 최대 100%까지 하락하고, 상승하는 것은 제한이 없으며, 위험이 높다. 따라서 네트워크 전략은 사용자가 잠재력이 있다고 생각하는 동전을 선택하도록 권장한다.
회귀 가격은 즉 초기 가격, 현재 가격과 초기 가격의 차이와 네트워크 크기가 얼마나 많은 포지션을 보유해야 하는지를 결정한다. 회귀 가격이 현재 가격보다 높게 설정되면 네트워크 전략은 더 많은 것을 할 것이고, 반대로 공허하게 될 것이다. 기본 회귀 가격은 전략의 시작 당시의 가격이다. 위험을 줄이기 위해, 많은 것을 할 것을 권장하는 네트워크, 자연스러운 아이디어는 회귀 가격을 변경할 수 없습니다. 가격 상승에도 불구하고 계속 많은 것을 보유하고, 자동 조정되지 않습니다.
첫 번째 전략을 시작할 때, 회귀 가격을 시작 가격의 1.6배로 설정하여, 그레드 전략은 가격이 현재 가격으로 1.6배로 떨어지는 것을 시작으로 이 부분 차이의 원인이 된 다중 포지션을 보유하게됩니다. 후기 가격이 회귀 가격 / 1.6을 초과하면 초기 가격을 다시 설정하여 항상 최소 60%의 차이를 유지합니다. 회귀 결과는 다음과 같습니다:
물론 시장이 더 낙관적이면 이 비율을 더 높게 설정할 수 있고, 결국 수익도 그에 따라 증가할 수 있습니다. 물론 시장이 하락하면 이러한 설정은 보유 위험을 증가시킵니다.