Skip to content

Commit

Permalink
Merge pull request #366 from enarjord/v5.8.2_oh
Browse files Browse the repository at this point in the history
V5.8.2 oh
  • Loading branch information
enarjord authored Dec 21, 2022
2 parents 196f1d8 + 65502b0 commit 83af2a5
Show file tree
Hide file tree
Showing 11 changed files with 787 additions and 433 deletions.
415 changes: 261 additions & 154 deletions binance.py

Large diffs are not rendered by default.

119 changes: 98 additions & 21 deletions bitget.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class BitgetBot(Bot):
def __init__(self, config: dict):
self.is_logged_into_user_stream = False
self.exchange = "bitget"
self.max_n_orders_per_batch = 50
self.max_n_cancellations_per_batch = 60
super().__init__(config)
self.base_endpoint = "https://api.bitget.com"
self.endpoints = {
Expand All @@ -44,6 +46,8 @@ def __init__(self, config: dict):
"ticker": "/api/mix/v1/market/ticker",
"open_orders": "/api/mix/v1/order/current",
"create_order": "/api/mix/v1/order/placeOrder",
"batch_orders": "/api/mix/v1/order/batch-orders",
"batch_cancel_orders": "/api/mix/v1/order/cancel-batch-orders",
"cancel_order": "/api/mix/v1/order/cancel-order",
"ticks": "/api/mix/v1/market/fills",
"fills": "/api/mix/v1/order/fills",
Expand Down Expand Up @@ -168,11 +172,22 @@ async def public_get(self, url: str, params: dict = {}) -> dict:
async def private_(
self, type_: str, base_endpoint: str, url: str, params: dict = {}, json_: bool = False
) -> dict:
def stringify(x):
if type(x) == bool:
return "true" if x else "false"
elif type(x) == float:
return format_float(x)
elif type(x) == int:
return str(x)
elif type(x) == list:
return [stringify(y) for y in x]
elif type(x) == dict:
return {k: stringify(v) for k, v in x.items()}
else:
return x

timestamp = int(time() * 1000)
params = {
k: ("true" if v else "false") if type(v) == bool else str(v) for k, v in params.items()
}
params = {k: stringify(v) for k, v in params.items()}
if type_ == "get":
url = url + "?" + urlencode(sort_dict_keys(params))
to_sign = str(timestamp) + type_.upper() + url
Expand Down Expand Up @@ -286,6 +301,13 @@ async def fetch_position(self) -> dict:

return position

async def execute_orders(self, orders: [dict]) -> [dict]:
if len(orders) == 0:
return []
if len(orders) == 1:
return [await self.execute_order(orders[0])]
return await self.execute_batch_orders(orders)

async def execute_order(self, order: dict) -> dict:
o = None
try:
Expand All @@ -307,6 +329,7 @@ async def execute_order(self, order: dict) -> dict:
custom_id = order["custom_id"] if "custom_id" in order else "0"
params["clientOid"] = f"{self.broker_code}#{custom_id}_{random_str}"
o = await self.private_post(self.endpoints["create_order"], params)
# print('debug create order', o, order)
if o["data"]:
# print('debug execute order', o)
return {
Expand All @@ -326,27 +349,81 @@ async def execute_order(self, order: dict) -> dict:
traceback.print_exc()
return {}

async def execute_cancellation(self, order: dict) -> dict:
cancellation = None
async def execute_batch_orders(self, orders: [dict]) -> [dict]:
executed = None
try:
cancellation = await self.private_post(
self.endpoints["cancel_order"],
{"symbol": self.symbol, "marginCoin": self.margin_coin, "orderId": order["order_id"]},
to_execute = []
orders_with_custom_ids = []
for order in orders:
params = {
"size": str(order["qty"]),
"side": self.order_side_map[order["side"]][order["position_side"]],
"orderType": order["type"],
"presetTakeProfitPrice": "",
"presetStopLossPrice": "",
}
if params["orderType"] == "limit":
params["timeInForceValue"] = "post_only"
params["price"] = str(order["price"])
else:
params["timeInForceValue"] = "normal"
random_str = f"{str(int(time() * 1000))[-6:]}_{int(np.random.random() * 10000)}"
custom_id = order["custom_id"] if "custom_id" in order else "0"
params["clientOid"] = order[
"custom_id"
] = f"{self.broker_code}#{custom_id}_{random_str}"
orders_with_custom_ids.append({**order, **{"symbol": self.symbol}})
to_execute.append(params)
executed = await self.private_post(
self.endpoints["batch_orders"],
{"symbol": self.symbol, "marginCoin": self.margin_coin, "orderDataList": to_execute},
)
return {
"symbol": self.symbol,
"side": order["side"],
"order_id": cancellation["data"]["orderId"],
"position_side": order["position_side"],
"qty": order["qty"],
"price": order["price"],
}
formatted = []
for ex in executed["data"]["orderInfo"]:
to_add = {"order_id": ex["orderId"], "custom_id": ex["clientOid"]}
for elm in orders_with_custom_ids:
if elm["custom_id"] == ex["clientOid"]:
to_add.update(elm)
formatted.append(to_add)
break
# print('debug execute batch orders', executed, orders, formatted)
return formatted
except Exception as e:
print(f"error cancelling order {order} {e}")
print_async_exception(cancellation)
print(f"error executing order {executed} {e}")
print_async_exception(executed)
traceback.print_exc()
self.ts_released["force_update"] = 0.0
return {}
return []

async def execute_cancellations(self, orders: [dict]) -> [dict]:
if not orders:
return []
cancellations = []
symbol = orders[0]["symbol"] if "symbol" in orders[0] else self.symbol
try:
cancellations = await self.private_post(
self.endpoints["batch_cancel_orders"],
{
"symbol": symbol,
"marginCoin": self.margin_coin,
"orderIds": [order["order_id"] for order in orders],
},
)

formatted = []
for oid in cancellations["data"]["order_ids"]:
to_add = {"order_id": oid}
for order in orders:
if order["order_id"] == oid:
to_add.update(order)
formatted.append(to_add)
break
# print('debug cancel batch orders', cancellations, orders, formatted)
return formatted
except Exception as e:
logging.error(f"error cancelling orders {orders} {e}")
print_async_exception(cancellations)
traceback.print_exc()
return []

async def fetch_account(self):
raise NotImplementedError("not implemented")
Expand Down Expand Up @@ -582,7 +659,7 @@ async def init_exchange_config(self):
)
print(res)
except Exception as e:
print(e)
print("error initiating exchange config", e)

def standardize_market_stream_event(self, data: dict) -> [dict]:
if "action" not in data or data["action"] != "update":
Expand Down
92 changes: 80 additions & 12 deletions bybit.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import aiohttp
import numpy as np

from njit_funcs import round_
from njit_funcs import round_, calc_diff
from passivbot import Bot, logging
from procedures import print_async_exception, print_
from pure_funcs import ts_to_date, sort_dict_keys, date_to_ts
Expand Down Expand Up @@ -41,7 +41,9 @@ def determine_pos_side(o: dict) -> str:
class BybitBot(Bot):
def __init__(self, config: dict):
self.exchange = "bybit"
self.min_notional = 0.0
self.min_notional = 1.0
self.max_n_orders_per_batch = 5
self.max_n_cancellations_per_batch = 10
super().__init__(config)
self.base_endpoint = "https://api.bybit.com"
if self.test_mode:
Expand All @@ -58,7 +60,7 @@ def init_market_type(self):
websockets_base_endpoint = "wss://stream.bybit.com"
if self.test_mode:
websockets_base_endpoint = "wss://stream-testnet.bybit.com"

if self.symbol.endswith("USDT"):
print("linear perpetual")
self.market_type += "_linear_perpetual"
Expand Down Expand Up @@ -117,7 +119,7 @@ def init_market_type(self):
self.spot_base_endpoint = "https://api.bybit.com"
if self.test_mode:
self.spot_base_endpoint = "https://api-testnet.bybit.com"

self.endpoints["spot_balance"] = "/spot/v1/account"
self.endpoints["balance"] = "/v2/private/wallet/balance"
self.endpoints["exchange_info"] = "/v2/public/symbols"
Expand Down Expand Up @@ -271,6 +273,31 @@ async def fetch_position(self) -> dict:
}
return position

async def execute_orders(self, orders: [dict]) -> [dict]:
if not orders:
return []
creations = []
for order in sorted(orders, key=lambda x: calc_diff(x["price"], self.price)):
creation = None
try:
creation = asyncio.create_task(self.execute_order(order))
creations.append((order, creation))
except Exception as e:
print(f"error creating order {order} {e}")
print_async_exception(creation)
traceback.print_exc()
results = []
for creation in creations:
result = None
try:
result = await creation[1]
results.append(result)
except Exception as e:
print(f"error creating order {creation} {e}")
print_async_exception(result)
traceback.print_exc()
return results

async def execute_order(self, order: dict) -> dict:
o = None
try:
Expand Down Expand Up @@ -317,6 +344,31 @@ async def execute_order(self, order: dict) -> dict:
traceback.print_exc()
return {}

async def execute_cancellations(self, orders: [dict]) -> [dict]:
if not orders:
return []
cancellations = []
for order in sorted(orders, key=lambda x: calc_diff(x["price"], self.price)):
cancellation = None
try:
cancellation = asyncio.create_task(self.execute_cancellation(order))
cancellations.append((order, cancellation))
except Exception as e:
print(f"error cancelling order {order} {e}")
print_async_exception(cancellation)
traceback.print_exc()
results = []
for cancellation in cancellations:
result = None
try:
result = await cancellation[1]
results.append(result)
except Exception as e:
print(f"error cancelling order {cancellation} {e}")
print_async_exception(result)
traceback.print_exc()
return results

async def execute_cancellation(self, order: dict) -> dict:
cancellation = None
try:
Expand All @@ -333,9 +385,17 @@ async def execute_cancellation(self, order: dict) -> dict:
"price": order["price"],
}
except Exception as e:
if cancellation is not None and "ret_code" in cancellation and cancellation["ret_code"] == 20001:
error_cropped = {k: v for k, v in cancellation.items() if k in ["ret_msg", "ret_code"]}
logging.error(f"error cancelling order {error_cropped} {order}") # neater error message
if (
cancellation is not None
and "ret_code" in cancellation
and cancellation["ret_code"] == 20001
):
error_cropped = {
k: v for k, v in cancellation.items() if k in ["ret_msg", "ret_code"]
}
logging.error(
f"error cancelling order {error_cropped} {order}"
) # neater error message
else:
print(f"error cancelling order {order} {e}")
print_async_exception(cancellation)
Expand Down Expand Up @@ -608,21 +668,29 @@ async def init_exchange_config(self):
print(res)
res = await self.private_post(
"/private/linear/position/set-leverage",
{"symbol": self.symbol, "buy_leverage": self.leverage, "sell_leverage": self.leverage},
{
"symbol": self.symbol,
"buy_leverage": self.leverage,
"sell_leverage": self.leverage,
},
)
print(res)
elif "inverse_perpetual" in self.market_type:
res = await self.private_post(
"/v2/private/position/switch-isolated",
{"symbol": self.symbol, "is_isolated": False,
"buy_leverage": self.leverage, "sell_leverage": self.leverage},
{
"symbol": self.symbol,
"is_isolated": False,
"buy_leverage": self.leverage,
"sell_leverage": self.leverage,
},
)
print('1', res)
print("1", res)
res = await self.private_post(
"/v2/private/position/leverage/save",
{"symbol": self.symbol, "leverage": self.leverage, "leverage_only": True},
)
print('2', res)
print("2", res)
except Exception as e:
print(e)

Expand Down
50 changes: 25 additions & 25 deletions configs/live/neat_grid_mode.example.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
{"config_name": "neat_grid_118_symbols_626days",
{"config_name": "neat_grid_118_symbols_688days",
"logging_level": 0,
"long": {"auto_unstuck_ema_dist": 0,
"auto_unstuck_wallet_exposure_threshold": 0.012195009245955374,
"long": {"auto_unstuck_ema_dist": 0.001,
"auto_unstuck_wallet_exposure_threshold": 0.1,
"backwards_tp": true,
"ema_span_0": 240,
"ema_span_1": 307.0566300659701,
"ema_span_0": 2245.681580255934,
"ema_span_1": 983.7519751474474,
"enabled": true,
"eprice_exp_base": 0.9814428052289045,
"eqty_exp_base": 1.8910056941476132,
"grid_span": 0.35120092600982644,
"initial_eprice_ema_dist": -0.0724883315452062,
"eprice_exp_base": 0.9,
"eqty_exp_base": 0.9,
"grid_span": 0.3634600582110678,
"initial_eprice_ema_dist": 0.006593185590130529,
"initial_qty_pct": 0.015,
"markup_range": 0.029915290808625504,
"max_n_entry_orders": 9,
"min_markup": 0.003,
"n_close_orders": 10,
"markup_range": 0.03989354389116942,
"max_n_entry_orders": 26,
"min_markup": 0.00390450048454419,
"n_close_orders": 30,
"wallet_exposure_limit": 0.1},
"short": {"auto_unstuck_ema_dist": 0.02,
"auto_unstuck_wallet_exposure_threshold": 0.010010044896137589,
"short": {"auto_unstuck_ema_dist": 0.004166734020707882,
"auto_unstuck_wallet_exposure_threshold": 0.09483563420728498,
"backwards_tp": true,
"ema_span_0": 3578.5992758249126,
"ema_span_1": 1300.2248624251254,
"ema_span_0": 240,
"ema_span_1": 240,
"enabled": true,
"eprice_exp_base": 0.9,
"eqty_exp_base": 2.741199913514829,
"grid_span": 0.35422351795434553,
"initial_eprice_ema_dist": 0.005310285956060753,
"eprice_exp_base": 0.9030929538070822,
"eqty_exp_base": 1.139844561045326,
"grid_span": 0.5588225833929379,
"initial_eprice_ema_dist": -0.0403097381673301,
"initial_qty_pct": 0.015,
"markup_range": 0.011750423363748088,
"max_n_entry_orders": 7,
"min_markup": 0.003,
"n_close_orders": 8,
"markup_range": 0.01710717452246016,
"max_n_entry_orders": 12,
"min_markup": 0.0032327368401944916,
"n_close_orders": 10,
"wallet_exposure_limit": 0.1}}
Loading

0 comments on commit 83af2a5

Please sign in to comment.