BitMEXの売買履歴をTradingViewチャートにプロットする方法
BitMEXの直近500件の売買履歴からPineスクリプトを生成するスクリプトを作成しました。
使い方
$ python mexhistory.py --apiKey xxxx --secret xxxx > pine.txt
出力されたPineスクリプトをTradingViewの新規スクリプトとして保存し、チャートにプロットしてください。
$ python mexhistory.py --apiKey xxxx --secret xxxx --since "2018/4/18 0:0:0" > pine.txt
--sinceオプションで指定した日付以降の売買履歴のみに絞ることができます。
スクリプト
code:mexhistory.py
# -*- coding: utf-8 -*-
import argparse
import dateutil.parser
import ccxt
import pandas as pd
import plotly.offline as offline
import plotly.graph_objs as go
import time
def store_datetime(str):
dt = dateutil.parser.parse(str)
return dt.strftime('%Y-%m-%dT%H:%M:%S')
parser = argparse.ArgumentParser(description="")
parser.add_argument("--symbol", type=str, default='BTC/USD')
parser.add_argument("--apiKey", type=str, default='')
parser.add_argument("--secret", type=str, default='')
parser.add_argument("--pine", action="store_true")
parser.add_argument("--since", type=store_datetime)
parser.add_argument("--plotly", action="store_true")
parser.add_argument("--testnet", action="store_true")
args = parser.parse_args()
exchange = ccxt.bitmex({
'apiKey': args.apiKey,
'secret': args.secret,
})
if args.testnet:
def fetch_trade_history(symbol=args.symbol, since=None, limit=None):
exchange.load_markets()
market = None
request = {}
if symbol is not None:
market = exchange.market(symbol)
if since is not None:
if limit is not None:
if 'filter' in request:
response = exchange.privateGetExecutionTradeHistory(request)
df = pd.DataFrame(response)
return df
if args.pine:
print(
'//@version=3\n'
'study("Bitmexトレード", overlay=true)\n'
'exec_time(transactTime) =>\n'
' result = false\n'
' delta = time - time1\n' ' if time < transactTime and transactTime < (time + delta)\n'
' result := true\n'
' result\n'
'pnl = 0\n'
'buy_price = close\n'
'buy_price := na\n'
'sell_price = close\n'
'sell_price := na\n'
)
else:
print('transactTime,symbol,execType,side,lastQty,lastPx,execCost,commission,execComm,ordType,orderQty,leavesQty,price,text,orderID,execCost_sum,execComm_sum,lastQty_sum,unrealizedPnl_sum')
count = 500
since = args.since
execCost_sum = 0
execComm_sum = 0
lastQty_sum = 0
unrealizedPnl_sum = 0
last_unrealizedPnl_sum = 0
chartIndex = []
lastPx = []
execComm = []
unrealizedPnl = []
longPnl = []
shortPnl = []
while True:
df = fetch_trade_history(since=since, limit=count)
for index, row in df.iterrows():
# トレード毎の損益
trade_pnl = 0
# 手数料の累計
execComm_sum = execComm_sum + row.execComm
if row.execType == "Trade":
# 執行コストの累計
execCost_sum = execCost_sum + row.execCost
# ポジション数更新
last_qty = lastQty_sum
if row.side == "Buy":
lastQty_sum = lastQty_sum + row.lastQty
else:
lastQty_sum = lastQty_sum - row.lastQty
# 現在の総合損益を計算
unrealizedPnl_sum = -(execComm_sum + execCost_sum + int(lastQty_sum / row.lastPx * 100000000))
# トレード毎の損益を計算
trade_pnl = unrealizedPnl_sum - last_unrealizedPnl_sum
# トレード数とトレード毎の損益計算
if last_qty < 0 and lastQty_sum >= 0:
shortPnl.append(trade_pnl)
last_unrealizedPnl_sum = unrealizedPnl_sum
elif last_qty > 0 and lastQty_sum <= 0:
longPnl.append(trade_pnl)
last_unrealizedPnl_sum = unrealizedPnl_sum
chartIndex.append(row.transactTime)
lastPx.append(row.lastPx)
execComm.append(execComm_sum)
unrealizedPnl.append(unrealizedPnl_sum)
if args.pine:
d = {
'transactTime': row.transactTime,
'side': row.side,
'lastQty': row.lastQty,
'price': row.price,
'buy_price': row.price if row.side == 'Buy' else 'na',
'sell_price': row.price if row.side == 'Sell' else 'na',
'pnl': unrealizedPnl_sum,
'timestamp': int(row.transactTime.timestamp())*1000,
}
print(
'// {transactTime} {side} {lastQty} {price}\n'
'if exec_time({timestamp})\n'
' pnl:={pnl}\n'
' buy_price:={buy_price}\n'
' sell_price:={sell_price}\n'.format(**d)
)
else:
print('{transactTime},{symbol},{execType},{side},{lastQty},{lastPx},{execCost},'
'{commission},{execComm},{ordType},{orderQty},{leavesQty},{price},"{text}",'
'{orderID},{execCost_sum},{execComm_sum},{lastQty_sum},{unrealizedPnl_sum}'.format(**row))
since = row.timestamp
if len(df.index) < count:
break
time.sleep(5)
if args.pine:
print(
'exec_price = na(buy_price) ? sell_price : buy_price\n'
'plot(exec_price, color=green, linewidth=2, transp=70)\n'
'//plot(pnl<0?-pnl:pnl, color=pnl>=0?green:orange, linewidth=4, style=area, transp=80)\n'
'plotshape(buy_price, style=shape.arrowup, location=location.belowbar, size=size.large)\n'
'plotshape(sell_price, style=shape.arrowdown, location=location.abovebar, size=size.large)\n'
)
else:
totalProfit = sum(longProfit) + sum(shortProfit)
totalLoss = sum(longLoss) + sum(shortLoss)
totalTrades = len(longPnl) + len(shortPnl)
totalWin = len(longProfit) + len(shortProfit)
totalLose = len(longLoss) + len(shortLoss)
longMax = max(longProfit) if len(longProfit) else 0
longMin = min(longLoss) if len(longLoss) else 0
shortMax = max(shortProfit) if len(shortProfit) else 0
shortMin = min(shortLoss) if len(shortLoss) else 0
d = {
'totalCount': len(longPnl) + len(shortPnl),
'longCount': len(longPnl),
'shortCount': len(shortPnl),
'totalPnl': sum(longPnl) + sum(shortPnl),
'longPnl': sum(longPnl),
'shortPnl': sum(shortPnl),
'totalWinCount': len(longProfit) + len(shortProfit),
'longWinCount': len(longProfit),
'shortWinCount': len(shortProfit),
'totalLossCount': len(longLoss) + len(shortLoss),
'longLossCount': len(longLoss),
'shortLossCount': len(shortLoss),
'totalProfit': sum(longProfit) + sum(shortProfit),
'longProfit': sum(longProfit),
'shortProfit': sum(shortProfit),
'totalLoss': sum(longLoss) + sum(shortLoss),
'longLoss': sum(longLoss),
'shortLoss': sum(shortLoss),
'totalPF': abs(totalProfit / totalLoss) if totalLoss else 0,
'longPF': abs(sum(longProfit) / sum(longLoss)) if sum(longLoss) else 0,
'shortPF': abs(sum(shortProfit) / sum(shortLoss)) if sum(shortLoss) else 0,
'totalWinRatio': totalWin / totalTrades if totalTrades else 0,
'longWinRatio': len(longProfit) / len(longPnl) if len(longPnl) else 0,
'shortWinRatio': len(shortProfit) / len(shortPnl) if len(shortPnl) else 0,
'avgTrade': (sum(longPnl) + sum(shortPnl)) / totalTrades if totalTrades else 0,
'avgWinTrade': (sum(longProfit) + sum(shortProfit))/totalWin if totalWin else 0,
'avgLossTrade': (sum(longLoss) + sum(shortLoss))/totalLose if totalLose else 0,
'avgLongTrade': sum(longPnl)/len(longPnl) if len(longPnl) else 0,
'avgLongWinTrade': sum(longProfit)/len(longProfit) if len(longProfit) else 0,
'avgLongLossTrade': sum(longLoss)/len(longLoss) if len(longLoss) else 0,
'avgShortTrade': sum(shortPnl)/len(shortPnl) if len(shortPnl) else 0,
'avgShortWinTrade': sum(shortProfit)/len(shortProfit) if len(shortProfit) else 0,
'avgShortLossTrade': sum(shortLoss)/len(shortLoss) if len(shortLoss) else 0,
'totalWinMax':max(longMax,shortMax),
'longWinMax':longMax,
'shortWinMax':shortMax,
'totalLossMin':min(longMin,shortMin),
'longLossMin':longMin,
'shortLossMin':shortMin,
}
print('Total,Long,Short')
print(
'Profit and Loss: {totalPnl},{longPnl},{shortPnl}\n'
'Profit: {totalProfit},{longProfit},{shortProfit}\n'
'Loss: {totalLoss},{longLoss},{shortLoss}\n'
'Profit Factor: {totalPF},{longPF},{shortPF}\n'
'Number of Trades: {totalCount},{longCount},{shortCount}\n'
'Number of Win: {totalWinCount},{longWinCount},{shortWinCount}\n'
'Number of Loss: {totalLossCount},{longLossCount},{shortLossCount}\n'
'Win ratio: {totalWinRatio},{longWinRatio},{shortWinRatio}\n'
'Avg Trade: {avgTrade},{avgLongTrade},{avgShortTrade}\n'
'Avg Win Trade: {avgWinTrade},{avgLongWinTrade},{avgShortWinTrade}\n'
'Avg Loss Trade: {avgLossTrade},{avgLongLossTrade},{avgShortLossTrade}\n'
'Max Win Trade: {totalWinMax},{longWinMax},{shortWinMax}\n'
'Max Loss Trade: {totalLossMin},{longLossMin},{shortLossMin}\n'
''.format(**d))
if args.plotly:
price_line = go.Scatter(
x = chartIndex,
y = lastPx,
mode = 'lines',
name = 'Price'
)
pnl_area = go.Scatter(
x = chartIndex,
y = unrealizedPnl,
yaxis='y2',
fill='tozeroy',
mode= 'none',
name='Profit and Loss')
# 2軸グラフレイアウト作成
layout = go.Layout(
title='Price and Pnl',
yaxis=dict(
title='Price'
),
yaxis2=dict(
title='Profit and Loss',
overlaying='y',
side='right'
)
)
fig = go.Figure(data=data, layout=layout)
offline.plot(fig, filename='sample.html', auto_open=False)
ビットコインアドレス
3MtsP5ZKAuVA5pH2mDTFpHxHPG2JWC4Kop