add cross + imb
This commit is contained in:
139
bot_new.py
139
bot_new.py
@@ -124,6 +124,18 @@ class StateManager:
|
|||||||
self.last_strategy_time = 0
|
self.last_strategy_time = 0
|
||||||
self.strategy_interval = 0.1
|
self.strategy_interval = 0.1
|
||||||
|
|
||||||
|
self.ema_fast_period = 5
|
||||||
|
self.ema_slow_period = 20
|
||||||
|
self.ema_prices = {sym: [] for sym in ["VALBZ", "VALE", "XLF"]}
|
||||||
|
self.ema_fast = {sym: None for sym in ["VALBZ", "VALE", "XLF"]}
|
||||||
|
self.ema_slow = {sym: None for sym in ["VALBZ", "VALE", "XLF"]}
|
||||||
|
self.prev_ema_fast = {sym: None for sym in ["VALBZ", "VALE", "XLF"]}
|
||||||
|
self.position_signal = {sym: 0 for sym in ["VALBZ", "VALE", "XLF"]}
|
||||||
|
self.bid_prices = {sym: None for sym in ["BOND", "VALBZ", "VALE", "GS", "MS", "WFC", "XLF"]}
|
||||||
|
self.ask_prices = {sym: None for sym in ["BOND", "VALBZ", "VALE", "GS", "MS", "WFC", "XLF"]}
|
||||||
|
self.bid_depths = {sym: 0 for sym in ["BOND", "VALBZ", "VALE", "GS", "MS", "WFC", "XLF"]}
|
||||||
|
self.ask_depths = {sym: 0 for sym in ["BOND", "VALBZ", "VALE", "GS", "MS", "WFC", "XLF"]}
|
||||||
|
|
||||||
def position_for_symbol(self, symbol):
|
def position_for_symbol(self, symbol):
|
||||||
return self.positions_by_symbol.get(symbol, 0)
|
return self.positions_by_symbol.get(symbol, 0)
|
||||||
|
|
||||||
@@ -213,30 +225,76 @@ class StateManager:
|
|||||||
order_id = self.next_order_id()
|
order_id = self.next_order_id()
|
||||||
self.exchange.send_convert_message(order_id, symbol, dir, size)
|
self.exchange.send_convert_message(order_id, symbol, dir, size)
|
||||||
|
|
||||||
def update_avg_prices(self, trade_message):
|
def calculate_ema(self, prices, period):
|
||||||
|
if len(prices) < period:
|
||||||
|
return None
|
||||||
|
alpha = 2 / (period + 1)
|
||||||
|
ema = prices[0]
|
||||||
|
for price in prices[1:]:
|
||||||
|
ema = alpha * price + (1 - alpha) * ema
|
||||||
|
return ema
|
||||||
|
|
||||||
|
def update_ema_prices(self, trade_message):
|
||||||
symbol = trade_message["symbol"]
|
symbol = trade_message["symbol"]
|
||||||
price = trade_message["price"]
|
price = trade_message["price"]
|
||||||
|
|
||||||
if symbol == "VALBZ":
|
if symbol not in ["VALBZ", "VALE", "XLF"]:
|
||||||
if len(self.average_valbz_price) < 5:
|
return
|
||||||
self.average_valbz_price.append(price)
|
|
||||||
else:
|
|
||||||
self.average_valbz_price.pop(0)
|
|
||||||
self.average_valbz_price.append(price)
|
|
||||||
|
|
||||||
elif symbol == "VALE":
|
self.ema_prices[symbol].append(price)
|
||||||
if len(self.average_vale_price) < 5:
|
max_len = self.ema_slow_period
|
||||||
self.average_vale_price.append(price)
|
if len(self.ema_prices[symbol]) > max_len:
|
||||||
else:
|
self.ema_prices[symbol].pop(0)
|
||||||
self.average_vale_price.pop(0)
|
|
||||||
self.average_vale_price.append(price)
|
|
||||||
|
|
||||||
elif symbol == "XLF":
|
self.prev_ema_fast[symbol] = self.ema_fast[symbol]
|
||||||
if len(self.average_xlf_price) < 25:
|
self.ema_fast[symbol] = self.calculate_ema(self.ema_prices[symbol], self.ema_fast_period)
|
||||||
self.average_xlf_price.append(price)
|
self.ema_slow[symbol] = self.calculate_ema(self.ema_prices[symbol], self.ema_slow_period)
|
||||||
else:
|
|
||||||
self.average_xlf_price.pop(0)
|
def get_cross_signal(self, symbol):
|
||||||
self.average_xlf_price.append(price)
|
if self.ema_fast[symbol] is None or self.ema_slow[symbol] is None:
|
||||||
|
return 0
|
||||||
|
if self.prev_ema_fast[symbol] is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
prev_fast = self.prev_ema_fast[symbol]
|
||||||
|
prev_slow = self.ema_slow[symbol]
|
||||||
|
curr_fast = self.ema_fast[symbol]
|
||||||
|
curr_slow = self.ema_slow[symbol]
|
||||||
|
|
||||||
|
if prev_fast <= prev_slow and curr_fast > curr_slow:
|
||||||
|
return 1
|
||||||
|
elif prev_fast >= prev_slow and curr_fast < curr_slow:
|
||||||
|
return -1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def update_book(self, book_message):
|
||||||
|
symbol = book_message["symbol"]
|
||||||
|
if symbol not in self.bid_prices:
|
||||||
|
return
|
||||||
|
|
||||||
|
buy = book_message.get("buy", [])
|
||||||
|
sell = book_message.get("sell", [])
|
||||||
|
|
||||||
|
if buy:
|
||||||
|
self.bid_prices[symbol] = buy[0][0]
|
||||||
|
self.bid_depths[symbol] = sum(depth for _, depth in buy[:3])
|
||||||
|
if sell:
|
||||||
|
self.ask_prices[symbol] = sell[0][0]
|
||||||
|
self.ask_depths[symbol] = sum(depth for _, depth in sell[:3])
|
||||||
|
|
||||||
|
def get_book_imbalance(self, symbol):
|
||||||
|
bid = self.bid_depths.get(symbol, 0)
|
||||||
|
ask = self.ask_depths.get(symbol, 0)
|
||||||
|
if bid + ask == 0:
|
||||||
|
return 0
|
||||||
|
return (bid - ask) / (bid + ask)
|
||||||
|
|
||||||
|
def get_fair_value_from_book(self, symbol):
|
||||||
|
bid = self.bid_prices.get(symbol)
|
||||||
|
ask = self.ask_prices.get(symbol)
|
||||||
|
if bid is not None and ask is not None:
|
||||||
|
return (bid + ask) // 2
|
||||||
|
return None
|
||||||
|
|
||||||
def can_add_position(self, symbol, size, is_buy):
|
def can_add_position(self, symbol, size, is_buy):
|
||||||
current = self.position_for_symbol(symbol)
|
current = self.position_for_symbol(symbol)
|
||||||
@@ -251,27 +309,30 @@ class StateManager:
|
|||||||
return
|
return
|
||||||
self.last_strategy_time = now
|
self.last_strategy_time = now
|
||||||
|
|
||||||
avg_valbz = self.get_average_price(self.average_valbz_price)
|
for sym in ["VALBZ", "VALE", "XLF"]:
|
||||||
avg_vale = self.get_average_price(self.average_vale_price)
|
ema_signal = self.get_cross_signal(sym)
|
||||||
avg_xlf = self.get_average_price(self.average_xlf_price)
|
imbalance = self.get_book_imbalance(sym)
|
||||||
|
fair = self.get_fair_value_from_book(sym)
|
||||||
|
|
||||||
if len(self.average_valbz_price) >= 5:
|
if fair is None:
|
||||||
sell_size = 1 if self.can_add_position("VALBZ", 1, False) else 0
|
continue
|
||||||
buy_size = 1 if self.can_add_position("VALBZ", 1, True) else 0
|
|
||||||
self.set_orders_in_symbol_for_direction("VALBZ", "SELL", {avg_valbz + 1: sell_size})
|
|
||||||
self.set_orders_in_symbol_for_direction("VALBZ", "BUY", {avg_valbz - 1: buy_size})
|
|
||||||
|
|
||||||
if len(self.average_vale_price) >= 5:
|
signal_strength = abs(ema_signal) + (1 if abs(imbalance) > 0.3 else 0)
|
||||||
sell_size = 1 if self.can_add_position("VALE", 1, False) else 0
|
if signal_strength == 0:
|
||||||
buy_size = 1 if self.can_add_position("VALE", 1, True) else 0
|
continue
|
||||||
self.set_orders_in_symbol_for_direction("VALE", "SELL", {avg_vale + 1: sell_size})
|
|
||||||
self.set_orders_in_symbol_for_direction("VALE", "BUY", {avg_vale - 1: buy_size})
|
|
||||||
|
|
||||||
if len(self.average_xlf_price) >= 25:
|
if ema_signal == 1 and self.position_signal[sym] <= 0:
|
||||||
sell_size = 1 if self.can_add_position("XLF", 1, False) else 0
|
size = 1 if self.can_add_position(sym, 1, True) else 0
|
||||||
buy_size = 1 if self.can_add_position("XLF", 1, True) else 0
|
if size > 0:
|
||||||
self.set_orders_in_symbol_for_direction("XLF", "SELL", {avg_xlf + 1: sell_size})
|
price = fair + 1
|
||||||
self.set_orders_in_symbol_for_direction("XLF", "BUY", {avg_xlf - 1: buy_size})
|
self.set_orders_in_symbol_for_direction(sym, "BUY", {price: size})
|
||||||
|
self.position_signal[sym] = 1
|
||||||
|
elif ema_signal == -1 and self.position_signal[sym] >= 0:
|
||||||
|
size = 1 if self.can_add_position(sym, 1, False) else 0
|
||||||
|
if size > 0:
|
||||||
|
price = fair - 1
|
||||||
|
self.set_orders_in_symbol_for_direction(sym, "SELL", {price: size})
|
||||||
|
self.position_signal[sym] = -1
|
||||||
|
|
||||||
self.execute_arb()
|
self.execute_arb()
|
||||||
|
|
||||||
@@ -357,12 +418,14 @@ def main():
|
|||||||
print(message)
|
print(message)
|
||||||
state_manager.on_fill(message)
|
state_manager.on_fill(message)
|
||||||
elif message["type"] == "trade":
|
elif message["type"] == "trade":
|
||||||
state_manager.update_avg_prices(message)
|
state_manager.update_ema_prices(message)
|
||||||
state_manager.execute_strategies()
|
state_manager.execute_strategies()
|
||||||
elif message["type"] == "ack":
|
elif message["type"] == "ack":
|
||||||
state_manager.on_ack(message)
|
state_manager.on_ack(message)
|
||||||
elif message["type"] == "out":
|
elif message["type"] == "out":
|
||||||
state_manager.on_out(message)
|
state_manager.on_out(message)
|
||||||
|
elif message["type"] == "book":
|
||||||
|
state_manager.update_book(message)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user