How to make "Market Depth" chart in Plotly/Python? - python

I'm currently trying to make a market depth chart like the one on BitMEX here (not enough rep to post images yet): https://user-images.githubusercontent.com/53675680/85238644-5311e180-b3fd-11ea-9865-94e3451f335c.png
import pandas as pd
from bitmex_websocket import BitMEXWebsocket
ws = BitMEXWebsocket(endpoint="https://testnet.bitmex.com/api/v1", symbol='XBTUSD', api_key=None, api_secret=None)
df = pd.DataFrame(ws.market_depth())
df.head()
symbol id side size price
0 XBTUSD 15500000000 Sell 1003 1000000.0
1 XBTUSD 15500000100 Sell 100001 999999.0
2 XBTUSD 15502119900 Sell 5000 978801.0
3 XBTUSD 15504648350 Sell 2191000 953516.5
4 XBTUSD 15515440800 Sell 300 845592.0
# ommitted fuction that gets current bitcoin price for sake of brevity
def get_current_price(symbol):
pass
current_price = request_history(symbol='XBTUSD', interval_mins=1, load_periods=1)['close'].iloc[0]
print(current_price)
Output: 9301.5
lower_bound = current_price * 0.99
upper_bound = current_price * 1.01
df = df.loc[(df.price > lower_bound) & (df.price < upper_bound)]
df.plot(kind='line', x='price', y='size')
My graph looks like this: https://user-images.githubusercontent.com/53675680/85238728-f8c55080-b3fd-11ea-95b3-1b35c3b958f6.png
I think the first step would be bucketing the prices and then displaying them as a bar chart but I'm not quite sure. Any ideas on how I would go about creating a graph that looks more like the one on BitMEX, preferably using plotly? Thanks.
EDIT
I've made some progress but still not close to matching what's on BitMex.
bins=[n for n in range(int(lower_bound), int(upper_bound), 10)]
lower_df = df.loc[df.price < current_price].price
upper_df = df.loc[df.price > current_price].price
plt.hist([lower_df, upper_df], bins=bins, edgecolor="k", color=['red', 'green'])
plt.xticks(bins[::5]) # display every 5th tick on x-axis
plt.show()
Image of Output: https://user-images.githubusercontent.com/53675680/85241059-7d1cd100-b408-11ea-8b2b-f39997767419.png
groups = df.groupby([pd.cut(df.price, bins)])['size'].sum()
groups.plot(kind='bar')
Image of Output: https://user-images.githubusercontent.com/53675680/85241076-902fa100-b408-11ea-941d-226927acb946.png

I coded a library to get Binance data to show you: https://github.com/nand0san/binpan_studio
Getting some data
import binpan
data = binpan.Symbol(symbol='btcusdt',
tick_interval='5m',
time_zone='UTC')
data.get_orderbook()
Price Quantity Side
0 21068.06 0.00267 ask
1 21068.03 0.00387 ask
2 21068.00 0.00125 ask
3 21067.86 0.00827 ask
4 21067.59 0.01355 ask
... ... ... ...
9995 19395.19 0.01007 bid
9996 19395.10 0.00729 bid
9997 19395.06 0.00112 bid
9998 19394.98 0.00688 bid
9999 19394.80 0.00241 bid
And plotting
data.plot_orderbook()
The function used with plotly is:
def orderbook_depth(df: pd.DataFrame,
accumulated=True,
title='Depth orderbook plot',
height=500,
plot_y="Quantity",
**kwargs):
ob = df.copy(deep=True)
if accumulated:
c_asks = ob[ob['Side'] == 'ask']['Quantity'][::-1].cumsum()
c_bids = ob[ob['Side'] == 'bid']['Quantity'].cumsum()
cumulated = pd.concat([c_asks, c_bids])
ob.loc[:, 'Accumulated'] = cumulated
plot_y = 'Accumulated'
fig = px.line(ob, x="Price", y=plot_y, color='Side', height=height, title=title, **kwargs)
fig.show()

Related

How do I add a daterange to open trades during when backtesting with backtrader?

I am trying to backtest a strategy where trades are only opened during 8.30 to 16.00 using backtrader.
Using the below attempt my code is running but returning no trades so my clsoing balane is the same as the opening. If I remove this filter my code is running correctly and trades are opening and closing so it is definitely the issue. Can anyone please help?
I have tried adding the datetime column of the data to a data feed using the below code:
` def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.datatime = mdates.num2date(self.datas[0].datetime)
self.datatsi = self.datas[0].tsi
self.datapsar = self.datas[0].psar
self.databbmiddle = self.datas[0].bbmiddle
self.datastlower = self.datas[0].stlower
self.datastupper = self.datas[0].stupper
# To keep track of pending orders
self.order = None`
I then used the following code to try filter by this date range:
# Check if we are in the market
if not self.position:
current_time = self.datatime[0].time()
if datetime.time(8, 30) < current_time < datetime.time(16, 0):
if self.datatsi < 0 and self.datastupper[0] > self.dataclose[0] and self.datastlower[1] < self.dataclose[1] and self.dataclose[0] < self.databbmiddle[0] and self.datapsar[0] > self.dataclose[0]:
self.log('SELL CREATE, %.2f' % self.dataclose[0])
# Keep track of the created order to avoid a 2nd order
os = self.sell_bracket(size=100,price=sp1, stopprice=sp2, limitprice=sp3)
self.orefs = [o.ref for o in os]
else:
o1 = self.buy(exectype=bt.Order.Limit,price=bp1,transmit=False)
print('{}: Oref {} / Buy at {}'.format(self.datetime.date(), o1.ref, bp1))
o2 = self.sell(exectype=bt.Order.Stop,price=bp2,parent=o1,transmit=False)
print('{}: Oref {} / Sell Stop at {}'.format(self.datetime.date(), o2.ref, bp2))
o3 = self.sell(exectype=bt.Order.Limit,price=bp3,parent=o1,transmit=True)
print('{}: Oref {} / Sell Limit at {}'.format(self.datetime.date(), o3.ref, bp3))
self.orefs = [o1.ref, o2.ref, o3.ref] # self.sell(size=100, exectype=bt.Order.Limit, price=self.data.close[0]+16, parent=self.order, parent_bracket=bt.Order.Market)

How can I price Digital option with short maturity

I am trying to price a Digital Call option using Quantlib Python package, but I have an inconsistent result. I am trying to price a deep ITM option with a 1 day maturity. The thing is that it returns me 0, which doesn't make sense. Could you please help me?
def Digital_Call(s0: float,
strike: float,
risk_free: float,
vol: float,
today: datetime,
maturity: datetime,
cash_payoff: float):
"Output: option_npv"
dividend_yield = 0
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, risk_free, ql.ActualActual()))
dividendTS = ql.YieldTermStructureHandle(ql.FlatForward(today, dividend_yield, ql.ActualActual()))
volatility = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(today, ql.NullCalendar(), vol, ql.ActualActual()))
initialValue = ql.QuoteHandle(ql.SimpleQuote(s0))
process = ql.BlackScholesMertonProcess(initialValue, dividendTS, riskFreeTS, volatility)
engine = ql.AnalyticEuropeanEngine(process)
option_type = ql.Option.Call
option = ql.VanillaOption(ql.CashOrNothingPayoff(option_type, strike, cash_payoff), ql.EuropeanExercise(maturity))
option.setPricingEngine(engine)
return option
s0=150
strike = 14.36
risk_free = 0.0302373913
#risk_free = 0
vol = 0.2567723271
today = datetime(2022,9,28)
maturity = datetime(2022,9,30) #it doesn't work with Maturity of both 1 & 2 days
cash_payoff = 30
It returns 0.
Thank You

binance api, i cant put an order with a price in dollar (not in quantity)

i try to put some orders at a specific price.
For example i would like to put 20 dollars to buy some ETHUSDT at 800 usdt but it gives me this error:
binance.exceptions.BinanceAPIException: APIError(code=-1106): Parameter 'quoteOrderQty' sent when not required.
there is my call function:
buy_order = client.create_order(
symbol = "ETHUSDT",
price = 800,
quoteOrderQty = 25,
side = client.SIDE_BUY,
type = client.ORDER_TYPE_LIMIT,
timeInForce = client.TIME_IN_FORCE_GTC)
but i dont have any error when i put this :
buy_order = client.create_test_order(symbol="ETHUSDT", side='BUY', type='MARKET', quoteOrderQty=10)
to be honnest actually i do that:
def putOrderBuy_at_price(self, symbol, amount, price):
monney_price = self.client.get_symbol_ticker(symbol=symbol)
# Calculate how much ETH $200 can buy
print(monney_price['price'])
i = 10
while i != 0:
try:
buy_quantity = round(amount / float(price), i)
print("-----------", buy_quantity)
#ETHUSDT
buy_order = self.client.create_order(
symbol = symbol,
price = price,
quantity = buy_quantity,
side = self.client.SIDE_BUY,
type = self.client.ORDER_TYPE_LIMIT,
timeInForce = self.client.TIME_IN_FORCE_GTC)
break
except Exception:
print(i)
i -= 1
And i think there is a better way for that.
Thanks for yours answers
quoteOrderQty is only for MARKET order.

Python crypto buy-sell bot

This is a simple trading bot working with gate.io api. It does almost what we want but 2 features are missing.
1-When I enter the token name in the terminal, it has to automatically buy it 3% more than the market price.
2-When the price rises as much as I have determined, it has to automatically sell back all the tokens it bought.
How can I add these features?
import ccxt, time
import utils.config
from utils.telegram_bot import post_message
# Create the GateIO exchange object using CCXT
exchange = ccxt.gateio({
'apiKey': utils.config.GATEIO_API_KEY,
'secret': utils.config.GATEIO_SECRET_KEY,
})
# Get the market and balance data from GateIO
markets = exchange.fetch_markets()
balance = exchange.fetch_total_balance()
# Get all the available symbols from GateIO
symbols = [symbol for symbol in [market['symbol'] for market in markets]]
# Placeholder for keeping the price at the time of buying
entryPrice = 0
def symbol_check(symbol):
if symbol in symbols:
print(f"Good news!, {symbol} exists in Gate.io")
return True
else:
print(f"Sorry, {symbol} does not exist in Gate.io")
return False
def buy(symbol):
global entryPrice
# Pick a price more than the last ticker data, to make sure that we can fulfill order
price = exchange.fetch_ticker(symbol)['last'] * 1.01
entryPrice = price
# Get the current USDT balance in GateIO
balance = exchange.fetch_total_balance()
coin = symbol.split('/')[0]
usdt_balance = balance['USDT']
# Calculate the amount of coin that we can buy, apply a small margin for rounding errors in balance
amount = (usdt_balance * 0.999) / (price)
# Create the limit buy order
exchange.create_limit_buy_order(symbol, amount=amount, price=price)
# Notify the user both on Telegram and CLI
message = f"You have {usdt_balance} USDT in your account. Buying {amount} {coin} for {price}"
print(message)
post_message(message)
def sell(symbol):
# Pick a price less than the last ticker data, to make sure that we can fulfill order
price = exchange.fetch_ticker(symbol)['last'] * 0.99
# Get the current coin balance in GateIO
balance = exchange.fetch_total_balance()
coin = symbol.split('/')[0]
coin_balance = balance[coin]
# Create the limit sell order
exchange.create_limit_sell_order(symbol, amount=coin_balance, price=price)
# Notify the user both on Telegram and CLI
message = f"You have {coin_balance} {coin} in your account. Selling them for {price}"
print(message)
post_message(message)
def sellBearish(symbol):
global entryPrice
bestPrice = exchange.fetch_ticker(symbol)['last']
balance = exchange.fetch_total_balance()
while True:
price = exchange.fetch_ticker(symbol)['last']
# Update the best price if we have a new best price
if price > bestPrice:
bestPrice = price
# If the price has dropped 3% percent w.r.t. the best price, sell the coins and get the profit
elif price < (0.97 * bestPrice):
coin = symbol.split('/')[0]
coin_balance = balance[coin]
exchange.create_limit_sell_order(symbol, amount=coin_balance, price=price*0.99)
# Notify the user both on Telegram and CLI
message = f"You have {coin_balance} {coin} in your account.\nSelling them for {price*0.99}\nYour profit is{price/entryPrice*100}"
print(message)
post_message(message)

It seems like I can't really get the output of my code to align properly using the format function. How am I supposed to do that?

I code that calculates the mean, standard deviation, modus, median, and quartile distance from a certain imported txt file with data.
However I've tried many things to properly sort and align the output to make it look somewhat neat, I figured the format function in Python would be my solution:
fmt = '{0:>18}: {1:>6.2f}'
for catlist in database:
huidigeCat = categories[counter]
fmt = '{0:>18}: {1:>6.2f}'
#numeriek
if isAlleenGetallen( catlist ):
#continue data ( floats )
if heeftFloat( catlist ):
floatslijst = maakFloats( catlist )
gemiddelde = getGemiddelde( floatslijst )
standaarddeviatie = getStandaarddeviatie( floatslijst,
gemiddelde )
print( huidigeCat, fmt.format("gemiddelde",(gemiddelde) ))
print(huidigeCat, fmt.format("standaarddeviatie",
(standaarddeviatie)))
#discrete data (integers)
else:
gesorteerdeLijst = sorted( maakIntegers( catlist ) )
mediaan = getMediaan( gesorteerdeLijst )
kwartielAfstand = getKwartielAfstand( gesorteerdeLijst )
print(huidigeCat, fmt.format("mediaan", mediaan))
print(huidigeCat, fmt.format("kwartielafstand",
kwartielAfstand))
#categoriaal
else:
#bereken de modus
#print( huidigeCat, "is Categoriaal")
modus = getModus( catlist )
print( huidigeCat, "Modus:", modus[0], "Aantal:", modus[1])
counter += 1
And this is the output of my current code:
Category Modus: Music/Movie/Game Aantal: 209
currency Modus: US Aantal: 663
sellerRating mediaan: 1853.00
sellerRating kwartielafstand: 2762.00
Duration mediaan: 7.00
Duration kwartielafstand: 2.00
endDay Modus: Mon Aantal: 292
ClosePrice gemiddelde: 38.85
ClosePrice standaarddeviatie: 100.10
OpenPrice gemiddelde: 14.21
OpenPrice standaarddeviatie: 49.38
Competitive? Modus: Yes Aantal: 569
How do I make this output somewhat readable?

Categories

Resources