async def create_base_proposals(self) -> List[ArbProposal]: """ Creates a list of 2 base proposals, no filter. :return: A list of 2 base proposals. """ tasks = [ self._spot_market_info.market.get_order_price( self._spot_market_info.trading_pair, True, self._order_amount), self._spot_market_info.market.get_order_price( self._spot_market_info.trading_pair, False, self._order_amount), self._perp_market_info.market.get_order_price( self._perp_market_info.trading_pair, True, self._order_amount), self._perp_market_info.market.get_order_price( self._perp_market_info.trading_pair, False, self._order_amount) ] prices = await safe_gather(*tasks, return_exceptions=True) spot_buy, spot_sell, perp_buy, perp_sell = [*prices] return [ ArbProposal( ArbProposalSide(self._spot_market_info, True, spot_buy), ArbProposalSide(self._perp_market_info, False, perp_sell), self._order_amount), ArbProposal( ArbProposalSide(self._spot_market_info, False, spot_sell), ArbProposalSide(self._perp_market_info, True, perp_buy), self._order_amount) ]
def test_check_budget_constraint(self): proposal = ArbProposal(ArbProposalSide(self.spot_market_info, False, Decimal("100")), ArbProposalSide(self.perp_market_info, True, Decimal("100")), Decimal("1")) self.spot_connector.set_balance(base_asset, 0.5) self.spot_connector.set_balance(quote_asset, 0) self.perp_connector.set_balance(base_asset, 0) self.perp_connector.set_balance(quote_asset, 21) # Since spot has 0.5 HBOT, not enough to sell on 1 order amount self.assertFalse(self.strategy.check_budget_constraint(proposal)) self.spot_connector.set_balance(base_asset, 1) self.assertTrue(self.strategy.check_budget_constraint(proposal)) # on perpetual you need at least 100/5 to open a position self.perp_connector.set_balance(quote_asset, 10) self.assertFalse(self.strategy.check_budget_constraint(proposal)) # There is no balance required to close a position self.perp_connector._account_positions[trading_pair] = Position( trading_pair, PositionSide.SHORT, Decimal("0"), Decimal("95"), Decimal("-1"), self.perp_connector.get_leverage(trading_pair) ) self.assertTrue(self.strategy.check_budget_constraint(proposal))
def test_arb_proposal(self): spot_connector = MagicMock() spot_connector.display_name = "Binance" spot_market_info = MarketTradingPairTuple(spot_connector, self.trading_pair, self.base_token, self.quote_token) perp_connector = MagicMock() perp_connector.display_name = "Binance Perpetual" perp_market_info = MarketTradingPairTuple(perp_connector, self.trading_pair, self.base_token, self.quote_token) spot_side = ArbProposalSide(spot_market_info, True, Decimal(100)) perp_side = ArbProposalSide(perp_market_info, False, Decimal(110)) proposal = ArbProposal(spot_side, perp_side, Decimal("1")) self.assertEqual(Decimal("0.1"), proposal.profit_pct()) expected_str = "Spot: Binance: Buy BTC at 100 USDT.\n" \ "Perpetual: Binance perpetual: Sell BTC at 110 USDT.\n" \ "Order amount: 1\n" \ "Profit: 10.00%" self.assertEqual(expected_str, str(proposal)) perp_side = ArbProposalSide(perp_market_info, True, Decimal(110)) with self.assertRaises(Exception) as context: proposal = ArbProposal(spot_side, perp_side, Decimal("1")) self.assertEqual( 'Spot and perpetual arb proposal cannot be on the same side.', str(context.exception))
def test_apply_slippage_buffers(self): proposal = ArbProposal(ArbProposalSide(self.spot_market_info, True, Decimal("100")), ArbProposalSide(self.perp_market_info, False, Decimal("100")), Decimal("1")) self.strategy._spot_market_slippage_buffer = Decimal("0.01") self.strategy._perp_market_slippage_buffer = Decimal("0.02") self.strategy.apply_slippage_buffers(proposal) self.assertEqual(Decimal("101"), proposal.spot_side.order_price) self.assertEqual(Decimal("98"), proposal.perp_side.order_price)
def exec_hedge_side(self, event, market_info, is_buy): p = ArbProposalSide( self._derivative_market_infos[market_info.trading_pair], not is_buy, event.price, event.amount) safe_ensure_future(self.execute_derivative_side(p))