From a38b0936fae08db4d4f53d1f2c4c80b7da7da314 Mon Sep 17 00:00:00 2001 From: cardosofede Date: Wed, 3 May 2023 20:55:52 -0300 Subject: [PATCH] (feat) clean up Strategy data class and add SingleMarketStrategyData --- utils/data_manipulation.py | 123 +++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/utils/data_manipulation.py b/utils/data_manipulation.py index aa5705d..91e811c 100644 --- a/utils/data_manipulation.py +++ b/utils/data_manipulation.py @@ -8,34 +8,79 @@ class StrategyData: orders: pd.DataFrame order_status: pd.DataFrame trade_fill: pd.DataFrame - config_file_name: str - def __post_init__(self): - self.trade_fill.loc[:, "net_amount"] = self.trade_fill['amount'] * self.trade_fill['trade_type'].apply(lambda x: 1 if x == 'BUY' else -1) - self.trade_fill.loc[:, "net_amount_quote"] = self.trade_fill['net_amount'] * self.trade_fill['price'] - self.trade_fill.loc[:, "cum_net_amount"] = self.trade_fill["net_amount"].cumsum() - self.trade_fill.loc[:, "unrealized_trade_pnl"] = -1 * self.trade_fill["net_amount_quote"].cumsum() - self.trade_fill.loc[:, "inventory_cost"] = self.trade_fill["cum_net_amount"] * self.trade_fill["price"] - self.trade_fill.loc[:, "realized_trade_pnl"] = self.trade_fill["unrealized_trade_pnl"] + self.trade_fill["inventory_cost"] - - def get_filtered_strategy_data(self, start_time: datetime.datetime, end_time: datetime.datetime): - orders = self.orders[(self.orders["creation_timestamp"] >= start_time) & (self.orders["creation_timestamp"] <= end_time)].copy() + def get_single_market_strategy_data(self, exchange: str, trading_pair: str): + orders = self.orders[(self.orders["market"] == exchange) & (self.orders["symbol"] == trading_pair)].copy() trade_fill = self.trade_fill[self.trade_fill["order_id"].isin(orders["id"])].copy() order_status = self.order_status[self.order_status["order_id"].isin(orders["id"])].copy() - return StrategyData( + return SingleMarketStrategyData( + exchange=exchange, + trading_pair=trading_pair, orders=orders, order_status=order_status, trade_fill=trade_fill, - config_file_name=self.config_file_name ) @property - def market(self): - return self.trade_fill["market"].unique()[0].split("_")[0] + def exchanges(self): + return self.trade_fill["market"].unique() @property - def symbol(self): - return self.trade_fill["symbol"].unique()[0] + def trading_pairs(self): + return self.trade_fill["symbol"].unique() + + @property + def start_time(self): + return self.orders["creation_timestamp"].min() + + @property + def end_time(self): + return self.orders["last_update_timestamp"].max() + + @property + def duration_seconds(self): + return (self.end_time - self.start_time).total_seconds() + + @property + def buys(self): + return self.trade_fill[self.trade_fill["trade_type"] == "BUY"] + + @property + def sells(self): + return self.trade_fill[self.trade_fill["trade_type"] == "SELL"] + + @property + def total_buy_trades(self): + return self.buys["amount"].count() + + @property + def total_sell_trades(self): + return self.sells["amount"].count() + + @property + def total_orders(self): + return self.total_buy_trades + self.total_sell_trades + + +@dataclass +class SingleMarketStrategyData: + exchange: str + trading_pair: str + orders: pd.DataFrame + order_status: pd.DataFrame + trade_fill: pd.DataFrame + + def get_filtered_strategy_data(self, start_date: datetime.datetime, end_date: datetime.datetime): + orders = self.orders[(self.orders["creation_timestamp"] >= start_date) & (self.orders["creation_timestamp"] <= end_date)].copy() + trade_fill = self.trade_fill[self.trade_fill["order_id"].isin(orders["id"])].copy() + order_status = self.order_status[self.order_status["order_id"].isin(orders["id"])].copy() + return SingleMarketStrategyData( + exchange=self.exchange, + trading_pair=self.trading_pair, + orders=orders, + order_status=order_status, + trade_fill=trade_fill, + ) @property def start_time(self): @@ -81,19 +126,6 @@ class StrategyData: def total_sell_trades(self): return self.sells["amount"].count() - - @property - def trade_pnl_usd(self): - # TODO: Review logic - buy_volume = self.buys["amount"].sum() * self.average_buy_price - sell_volume = self.sells["amount"].sum() * self.average_sell_price - inventory_change_volume = self.inventory_change_base_asset * self.end_price - return sell_volume - buy_volume + inventory_change_volume - - @property - def inventory_change_base_asset(self): - return self.total_buy_amount - self.total_sell_amount - @property def total_orders(self): return self.total_buy_trades + self.total_sell_trades @@ -112,28 +144,13 @@ class StrategyData: def price_change(self): return (self.end_price - self.start_price) / self.start_price - -@dataclass -class BotData: - orders: pd.DataFrame - order_status: pd.DataFrame - trade_fill: pd.DataFrame - - def get_strategy_data(self, config_file_name: str): - orders_filtered = self.orders[self.orders["config_file_path"] == config_file_name].copy() - order_status_filtered = self.order_status[ - self.order_status["order_id"].isin(orders_filtered["id"])].copy() - trade_fill_filtered = self.trade_fill[self.trade_fill["config_file_path"] == config_file_name].copy() - return StrategyData(orders_filtered, order_status_filtered, trade_fill_filtered, config_file_name) + @property + def trade_pnl_usd(self): + buy_volume = self.buys["amount"].sum() * self.average_buy_price + sell_volume = self.sells["amount"].sum() * self.average_sell_price + inventory_change_volume = self.inventory_change_base_asset * self.end_price + return sell_volume - buy_volume + inventory_change_volume @property - def start_time(self): - return self.orders["creation_timestamp"].min() - - @property - def end_time(self): - return self.orders["last_update_timestamp"].max() - - @property - def duration_minutes(self): - return (self.end_time - self.start_time).seconds / 60 \ No newline at end of file + def inventory_change_base_asset(self): + return self.total_buy_amount - self.total_sell_amount