Пример #1
0
    def test_performance_metrics(self):
        rate_oracle = RateOracle()
        rate_oracle._prices["USDT-HBOT"] = Decimal("5")
        RateOracle._shared_instance = rate_oracle

        trade_fee = AddedToCostTradeFee(
            flat_fees=[TokenAmount(quote, Decimal("0"))])
        trades = [
            TradeFill(
                config_file_path="some-strategy.yml",
                strategy="pure_market_making",
                market="binance",
                symbol=trading_pair,
                base_asset=base,
                quote_asset=quote,
                timestamp=int(time.time()),
                order_id="someId0",
                trade_type="BUY",
                order_type="LIMIT",
                price=100,
                amount=10,
                trade_fee=trade_fee.to_json(),
                exchange_trade_id="someExchangeId0",
                position=PositionAction.NIL.value,
            ),
            TradeFill(
                config_file_path="some-strategy.yml",
                strategy="pure_market_making",
                market="binance",
                symbol=trading_pair,
                base_asset=base,
                quote_asset=quote,
                timestamp=int(time.time()),
                order_id="someId1",
                trade_type="SELL",
                order_type="LIMIT",
                price=120,
                amount=15,
                trade_fee=trade_fee.to_json(),
                exchange_trade_id="someExchangeId1",
                position=PositionAction.NIL.value,
            )
        ]
        cur_bals = {base: 100, quote: 10000}
        metrics = asyncio.get_event_loop().run_until_complete(
            PerformanceMetrics.create(trading_pair, trades, cur_bals))
        self.assertEqual(Decimal("799"), metrics.trade_pnl)
        print(metrics)
Пример #2
0
    def test_get_trade_for_config(self):
        recorder = MarketsRecorder(sql=self.manager,
                                   markets=[self],
                                   config_file_path=self.config_file_path,
                                   strategy_name=self.strategy_name)

        with self.manager.get_new_session() as session:
            with session.begin():
                trade_fill_record = TradeFill(
                    config_file_path=self.config_file_path,
                    strategy=self.strategy_name,
                    market=self.display_name,
                    symbol=self.symbol,
                    base_asset=self.base,
                    quote_asset=self.quote,
                    timestamp=int(time.time()),
                    order_id="OID1",
                    trade_type=TradeType.BUY.name,
                    order_type=OrderType.LIMIT.name,
                    price=Decimal(1000),
                    amount=Decimal(1),
                    leverage=1,
                    trade_fee=AddedToCostTradeFee().to_json(),
                    exchange_trade_id="EOID1",
                    position=PositionAction.NIL.value)
                session.add(trade_fill_record)

            fill_id = trade_fill_record.exchange_trade_id

        trades = recorder.get_trades_for_config("test_config")
        self.assertEqual(1, len(trades))
        self.assertEqual(fill_id, trades[0].exchange_trade_id)
Пример #3
0
    def _did_fill_order(self, event_tag: int, market: ConnectorBase,
                        evt: OrderFilledEvent):
        if threading.current_thread() != threading.main_thread():
            self._ev_loop.call_soon_threadsafe(self._did_fill_order, event_tag,
                                               market, evt)
            return

        base_asset, quote_asset = evt.trading_pair.split("-")
        timestamp: int = self.db_timestamp
        event_type: MarketEvent = self.market_event_tag_map[event_tag]
        order_id: str = evt.order_id

        with self._sql_manager.get_new_session() as session:
            with session.begin():
                # Try to find the order record, and update it if necessary.
                order_record: Optional[Order] = session.query(Order).filter(
                    Order.id == order_id).one_or_none()
                if order_record is not None:
                    order_record.last_status = event_type.name
                    order_record.last_update_timestamp = timestamp

                # Order status and trade fill record should be added even if the order record is not found, because it's
                # possible for fill event to come in before the order created event for market orders.
                order_status: OrderStatus = OrderStatus(order_id=order_id,
                                                        timestamp=timestamp,
                                                        status=event_type.name)

                trade_fill_record: TradeFill = TradeFill(
                    config_file_path=self.config_file_path,
                    strategy=self.strategy_name,
                    market=market.display_name,
                    symbol=evt.trading_pair,
                    base_asset=base_asset,
                    quote_asset=quote_asset,
                    timestamp=timestamp,
                    order_id=order_id,
                    trade_type=evt.trade_type.name,
                    order_type=evt.order_type.name,
                    price=Decimal(evt.price)
                    if evt.price == evt.price else Decimal(0),
                    amount=Decimal(evt.amount),
                    leverage=evt.leverage if evt.leverage else 1,
                    trade_fee=evt.trade_fee.to_json(),
                    exchange_trade_id=evt.exchange_trade_id,
                    position=evt.position
                    if evt.position else PositionAction.NIL.value,
                )
                session.add(order_status)
                session.add(trade_fill_record)
                self.save_market_states(self._config_file_path,
                                        market,
                                        session=session)

                market.add_trade_fills_from_market_recorder({
                    TradeFillOrderDetails(trade_fill_record.market,
                                          trade_fill_record.exchange_trade_id,
                                          trade_fill_record.symbol)
                })
                self.append_to_csv(trade_fill_record)
 def save_trade_fill_records(
         self, trade_price_amount_list,
         market_trading_pair_tuple: MarketTradingPairTuple, order_type,
         start_time, strategy):
     trade_records: List[TradeFill] = []
     for trade in self.create_trade_fill_records(trade_price_amount_list,
                                                 market_trading_pair_tuple,
                                                 order_type, start_time,
                                                 strategy):
         trade_records.append(TradeFill(**trade))
     self.trade_fill_sql.get_shared_session().add_all(trade_records)
Пример #5
0
    def _did_fill_order(self, event_tag: int, market: MarketBase,
                        evt: OrderFilledEvent):
        if threading.current_thread() != threading.main_thread():
            self._ev_loop.call_soon_threadsafe(self._did_fill_order, event_tag,
                                               market, evt)
            return

        session: Session = self.session
        base_asset, quote_asset = market.split_trading_pair(evt.trading_pair)
        timestamp: int = self.db_timestamp
        event_type: MarketEvent = self.market_event_tag_map[event_tag]
        order_id: str = evt.order_id

        # Try to find the order record, and update it if necessary.
        order_record: Optional[Order] = session.query(Order).filter(
            Order.id == order_id).one_or_none()
        if order_record is not None:
            order_record.last_status = event_type.name
            order_record.last_update_timestamp = timestamp

        # Order status and trade fill record should be added even if the order record is not found, because it's
        # possible for fill event to come in before the order created event for market orders.
        order_status: OrderStatus = OrderStatus(order_id=order_id,
                                                timestamp=timestamp,
                                                status=event_type.name)
        trade_fill_record: TradeFill = TradeFill(
            config_file_path=self.config_file_path,
            strategy=self.strategy_name,
            market=market.display_name,
            symbol=evt.trading_pair,
            base_asset=base_asset,
            quote_asset=quote_asset,
            timestamp=timestamp,
            order_id=order_id,
            trade_type=evt.trade_type.name,
            order_type=evt.order_type.name,
            price=float(evt.price) if evt.price == evt.price else 0,
            amount=float(evt.amount),
            trade_fee=TradeFee.to_json(evt.trade_fee),
            exchange_trade_id=evt.exchange_trade_id)
        session.add(order_status)
        session.add(trade_fill_record)
        self.save_market_states(self._config_file_path, market, no_commit=True)
        session.commit()
        self.append_to_csv(trade_fill_record)
Пример #6
0
    def test_attribute_names_for_file_export_are_valid(self):
        trade_fill = TradeFill(config_file_path=self.config_file_path,
                               strategy=self.strategy_name,
                               market=self.display_name,
                               symbol=self.symbol,
                               base_asset=self.base,
                               quote_asset=self.quote,
                               timestamp=int(time.time()),
                               order_id="OID1",
                               trade_type=TradeType.BUY.name,
                               order_type=OrderType.LIMIT.name,
                               price=Decimal(1000),
                               amount=Decimal(1),
                               leverage=1,
                               trade_fee=AddedToCostTradeFee().to_json(),
                               exchange_trade_id="EOID1",
                               position="NILL")

        values = [
            getattr(trade_fill, attribute)
            for attribute in TradeFill.attribute_names_for_file_export()
        ]

        expected_values = [
            trade_fill.exchange_trade_id,
            trade_fill.config_file_path,
            trade_fill.strategy,
            trade_fill.market,
            trade_fill.symbol,
            trade_fill.base_asset,
            trade_fill.quote_asset,
            trade_fill.timestamp,
            trade_fill.order_id,
            trade_fill.trade_type,
            trade_fill.order_type,
            trade_fill.price,
            trade_fill.amount,
            trade_fill.leverage,
            trade_fill.trade_fee,
            trade_fill.position,
        ]

        self.assertEqual(expected_values, values)
Пример #7
0
    def test_calculate_fees_in_quote_for_one_trade_fill_with_fees_different_tokens(
            self):
        rate_oracle = RateOracle()
        rate_oracle._prices["DAI-COINALPHA"] = Decimal("2")
        rate_oracle._prices["USDT-DAI"] = Decimal("0.9")
        RateOracle._shared_instance = rate_oracle

        performance_metric = PerformanceMetrics()
        flat_fees = [
            TokenAmount(token="USDT", amount=Decimal("10")),
            TokenAmount(token="DAI", amount=Decimal("5")),
        ]
        trade = TradeFill(
            config_file_path="some-strategy.yml",
            strategy="pure_market_making",
            market="binance",
            symbol="HBOT-COINALPHA",
            base_asset="HBOT",
            quote_asset="COINALPHA",
            timestamp=int(time.time()),
            order_id="someId0",
            trade_type="BUY",
            order_type="LIMIT",
            price=1000,
            amount=1,
            trade_fee=AddedToCostTradeFee(percent=Decimal("0.1"),
                                          percent_token="COINALPHA",
                                          flat_fees=flat_fees).to_json(),
            exchange_trade_id="someExchangeId0",
            position=PositionAction.NIL.value,
        )

        self.async_run_with_timeout(
            performance_metric._calculate_fees(quote="COINALPHA",
                                               trades=[trade]))

        expected_fee_amount = Decimal(str(trade.amount)) * Decimal(
            str(trade.price)) * Decimal("0.1")
        expected_fee_amount += flat_fees[0].amount * Decimal("0.9") * Decimal(
            "2")
        expected_fee_amount += flat_fees[1].amount * Decimal("2")
        self.assertEqual(expected_fee_amount, performance_metric.fee_in_quote)
Пример #8
0
 def get_trades(self) -> List[TradeFill]:
     trade_fee = AddedToCostTradeFee(percent=Decimal("5"))
     trades = [
         TradeFill(
             config_file_path=f"{self.mock_strategy_name}.yml",
             strategy=self.mock_strategy_name,
             market="binance",
             symbol="BTC-USDT",
             base_asset="BTC",
             quote_asset="USDT",
             timestamp=int(time.time()),
             order_id="someId",
             trade_type="BUY",
             order_type="LIMIT",
             price=1,
             amount=2,
             leverage=1,
             trade_fee=trade_fee.to_json(),
             exchange_trade_id="someExchangeId",
         )
     ]
     return trades
Пример #9
0
 def get_trades() -> List[TradeFill]:
     trade_fee = TradeFee(percent=Decimal("5"))
     trades = [
         TradeFill(
             id=1,
             config_file_path="some-strategy.yml",
             strategy="pure_market_making",
             market="binance",
             symbol="BTC-USDT",
             base_asset="BTC",
             quote_asset="USDT",
             timestamp=int(time.time()),
             order_id="someId",
             trade_type="BUY",
             order_type="LIMIT",
             price=1,
             amount=2,
             leverage=1,
             trade_fee=TradeFee.to_json(trade_fee),
             exchange_trade_id="someExchangeId",
         )
     ]
     return trades
Пример #10
0
    def test_list_trades(self, notify_mock):
        global_config_map["tables_format"].value = "psql"

        captures = []
        notify_mock.side_effect = lambda s: captures.append(s)
        self.app.strategy_file_name = f"{self.mock_strategy_name}.yml"

        trade_fee = AddedToCostTradeFee(percent=Decimal("5"))
        order_id = PaperTradeExchange.random_order_id(order_side="BUY",
                                                      trading_pair="BTC-USDT")
        with self.app.trade_fill_db.get_new_session() as session:
            o = Order(
                id=order_id,
                config_file_path=f"{self.mock_strategy_name}.yml",
                strategy=self.mock_strategy_name,
                market="binance",
                symbol="BTC-USDT",
                base_asset="BTC",
                quote_asset="USDT",
                creation_timestamp=0,
                order_type="LMT",
                amount=4,
                leverage=0,
                price=3,
                last_status="PENDING",
                last_update_timestamp=0,
            )
            session.add(o)
            for i in [1, 2]:
                t = TradeFill(
                    config_file_path=f"{self.mock_strategy_name}.yml",
                    strategy=self.mock_strategy_name,
                    market="binance",
                    symbol="BTC-USDT",
                    base_asset="BTC",
                    quote_asset="USDT",
                    timestamp=i,
                    order_id=order_id,
                    trade_type="BUY",
                    order_type="LIMIT",
                    price=i,
                    amount=2,
                    leverage=1,
                    trade_fee=trade_fee.to_json(),
                    exchange_trade_id=f"someExchangeId{i}",
                )
                session.add(t)
            session.commit()

        self.app.list_trades(start_time=0)

        self.assertEqual(1, len(captures))

        creation_time_str = str(datetime.datetime.fromtimestamp(0))

        df_str_expected = (
            f"\n  Recent trades:"
            f"\n    +---------------------+------------+----------+--------------+--------+---------+----------+------------+------------+-------+"  # noqa: E501
            f"\n    | Timestamp           | Exchange   | Market   | Order_type   | Side   |   Price |   Amount |   Leverage | Position   | Age   |"  # noqa: E501
            f"\n    |---------------------+------------+----------+--------------+--------+---------+----------+------------+------------+-------|"  # noqa: E501
            f"\n    | {creation_time_str} | binance    | BTC-USDT | limit        | buy    |       1 |        2 |          1 | NIL        | n/a   |"  # noqa: E501
            f"\n    | {creation_time_str} | binance    | BTC-USDT | limit        | buy    |       2 |        2 |          1 | NIL        | n/a   |"  # noqa: E501
            f"\n    +---------------------+------------+----------+--------------+--------+---------+----------+------------+------------+-------+"  # noqa: E501
        )

        self.assertEqual(df_str_expected, captures[0])