Exemplo n.º 1
0
def test_valid_rmul():
    # Quantity
    size = Quantity(BTC, 5)
    p = Price(50, USD / BTC)
    q = size * p
    assert isinstance(q, Quantity)
    assert q.size == 250
    assert q.instrument == USD

    # Quantity with Path ID
    size = Quantity(BTC, 5, path_id="fake_id")
    p = Price(50, USD / BTC)
    q = size * p
    assert isinstance(q, Quantity)
    assert q.size == 250
    assert q.instrument == USD
    assert q.path_id == "fake_id"

    # int
    p1 = 5
    p2 = Price(50, USD / BTC)
    p = p1 * p2
    assert p.rate == 250
    assert p.pair == USD / BTC

    # float
    p1 = 5.0
    p2 = Price(50, USD / BTC)
    p = p1 * p2
    assert p.rate == 250
    assert p.pair == USD / BTC
Exemplo n.º 2
0
def test_valid_rtruediv():

    # Quantity
    size = Quantity(USD, 50)
    p = Price(5, USD / BTC)
    q = size / p
    assert isinstance(q, Quantity)
    assert q.size == 10
    assert q.instrument == BTC

    # Quantity with Path ID
    size = Quantity(USD, 50, "fake_id")
    p = Price(5, USD / BTC)
    q = size / p
    assert isinstance(q, Quantity)
    assert q.size == 10
    assert q.instrument == BTC
    assert q.path_id == "fake_id"

    # int
    p1 = 50
    p2 = Price(5, USD / BTC)
    p = p1 / p2
    assert p.rate == 10
    assert p.pair == BTC / USD

    # float
    p1 = 50.0
    p2 = Price(5, USD / BTC)
    p = p1 / p2
    assert p.rate == 10
    assert p.pair == BTC / USD
    def _execute_sell_order(self, order: 'Order', base_wallet: 'Wallet',
                            quote_wallet: 'Wallet',
                            current_price: float) -> Trade:
        price = self._contain_price(current_price)

        if order.type == TradeType.LIMIT and order.price > current_price:
            return None

        commission = Quantity(order.pair.base, order.size * self._commission,
                              order.path_id)
        size = self._contain_size(order.size - commission.size)
        quantity = Quantity(order.pair.base, size, order.path_id)

        trade = Trade(order_id=order.id,
                      exchange_id=self.id,
                      step=self.clock.step,
                      pair=order.pair,
                      side=TradeSide.SELL,
                      trade_type=order.type,
                      quantity=quantity,
                      price=price,
                      commission=commission)

        # self._slippage_model.adjust_trade(trade)

        quote_size = trade.size / trade.price * (trade.price / order.price)

        quote_wallet -= Quantity(order.pair.quote, quote_size, order.path_id)
        base_wallet += quantity
        base_wallet -= commission

        return trade
Exemplo n.º 4
0
def test_total_balance():

    wallet = Wallet(exchange, 10000 * USD)
    wallet += Quantity(USD, 500, path_id=path_id)
    wallet += Quantity(USD, 700, path_id=other_id)

    assert wallet.total_balance == 11200 * USD
Exemplo n.º 5
0
def test_total_balance():

    wallet = Wallet(exchange, 10000 * USD)
    wallet.deposit(quantity=Quantity(USD, 500, path_id=path_id), reason="test")
    wallet.deposit(quantity=Quantity(USD, 700, path_id=other_id),
                   reason="test")

    assert wallet.total_balance == 11200 * USD
Exemplo n.º 6
0
def test_invalid_rtruediv():

    # Quantity with instrument different than the quote
    p2 = Quantity(USD, 50)
    p1 = Price(50, BTC / USD)
    with pytest.raises(IncompatiblePriceQuantityOperation):
        p1 / p2
Exemplo n.º 7
0
def test_exchange_with_wallets_feed():

    ex1 = Exchange("coinbase",
                   service=execute_order)(Array("USD-BTC", [7000, 7500, 8300]),
                                          Array("USD-ETH", [200, 212, 400]))

    ex2 = Exchange("binance",
                   service=execute_order)(Array("USD-BTC", [7005, 7600, 8200]),
                                          Array("USD-ETH", [201, 208, 402]),
                                          Array("USD-LTC", [56, 52, 60]))

    wallet_btc = Wallet(ex1, 10 * BTC)
    wallet_btc_ds = create_wallet_source(wallet_btc)

    wallet_usd = Wallet(ex2, 1000 * USD)
    wallet_usd -= 400 * USD
    wallet_usd += Quantity(USD, 400, path_id="fake_id")
    wallet_usd_ds = create_wallet_source(wallet_usd, include_worth=False)

    feed = DataFeed([ex1, ex2, wallet_btc_ds, wallet_usd_ds])

    assert feed.next() == {
        "coinbase:/USD-BTC": 7000,
        "coinbase:/USD-ETH": 200,
        "coinbase:/BTC:/free": 10,
        "coinbase:/BTC:/locked": 0,
        "coinbase:/BTC:/total": 10,
        "coinbase:/BTC:/worth": 70000,
        "binance:/USD-BTC": 7005,
        "binance:/USD-ETH": 201,
        "binance:/USD-LTC": 56,
        "binance:/USD:/free": 600,
        "binance:/USD:/locked": 400,
        "binance:/USD:/total": 1000
    }
Exemplo n.º 8
0
    def execute(self, exchange: 'Exchange'):
        self.status = OrderStatus.OPEN

        instrument = self.side.instrument(self.pair)
        wallet = self.portfolio.get_wallet(exchange.id, instrument=instrument)

        if self.path_id not in wallet.locked.keys():
            try:
                wallet -= self.size * instrument
            except InsufficientFunds:
                size = wallet.balance.size
                wallet -= size * instrument
                self.quantity = Quantity(instrument,
                                         size,
                                         path_id=self.path_id)

            wallet += self.quantity

        if self.portfolio.order_listener:
            self.attach(self.portfolio.order_listener)

        for listener in self._listeners or []:
            listener.on_execute(self, exchange)

        exchange.execute_order(self, self.portfolio)
Exemplo n.º 9
0
    def locked_balance(self) -> 'Quantity':
        """The total balance of the wallet locked in orders."""
        locked_balance = Quantity(self.instrument, 0)

        for quantity in self.locked.values():
            locked_balance += quantity.size

        return locked_balance
Exemplo n.º 10
0
def test_invalid_isub():

    # Add to balance with locked path_id
    wallet = Wallet(exchange, 10000 * USD)
    wallet += Quantity(USD, 500, path_id=path_id)
    wallet += Quantity(USD, 700, path_id=other_id)

    with pytest.raises(InsufficientFunds):
        wallet -= 11000 * USD

    with pytest.raises(InsufficientFunds):
        wallet -= Quantity(USD, 750, path_id)

    with pytest.raises(InsufficientFunds):
        wallet -= Quantity(USD, 750, path_id)

    with pytest.raises(IncompatibleInstrumentOperation):
        wallet -= 500 * BTC
Exemplo n.º 11
0
    def balance(self, instrument: Instrument) -> Quantity:
        """The total balance of the portfolio in a specific instrument available for use."""
        balance = Quantity(instrument, 0)

        for (_, symbol), wallet in self._wallets.items():
            if symbol == instrument.symbol:
                balance += wallet.balance

        return balance
Exemplo n.º 12
0
    def locked_balance(self, instrument: Instrument) -> Quantity:
        """The total balance of the portfolio in a specific instrument locked in orders."""
        balance = Quantity(instrument, 0)

        for (_, symbol), wallet in self._wallets.items():
            if symbol == instrument.symbol:
                balance += wallet.locked_balance

        return balance
Exemplo n.º 13
0
def test_deallocate():
    wallet = Wallet(exchange, 10000 * USD)
    wallet += Quantity(USD, 500, path_id=path_id)
    wallet += Quantity(USD, 700, path_id=other_id)

    assert wallet.balance == 10000 * USD
    assert wallet.locked[path_id] == 500 * USD
    assert wallet.locked[other_id] == 700 * USD

    wallet.deallocate(path_id)

    assert wallet.balance == 10500 * USD
    assert path_id not in wallet.locked.keys()
    assert wallet.locked[other_id] == 700 * USD

    wallet.deallocate(other_id)

    assert wallet.balance == 11200 * USD
    assert other_id not in wallet.locked.keys()
Exemplo n.º 14
0
    def _execute_buy_order(self, order: 'Order', base_wallet: 'Wallet',
                           quote_wallet: 'Wallet',
                           current_price: float) -> Trade:
        price = self._contain_price(current_price)

        if order.type == TradeType.LIMIT and order.price < current_price:
            return None

        commission = Quantity(order.pair.base, order.size * self._commission,
                              order.path_id)
        base_size = self._contain_size(order.size - commission.size)

        if order.type == TradeType.MARKET:
            scale = order.price / price
            base_size = self._contain_size(scale * order.size -
                                           commission.size)

        base_wallet -= commission

        try:
            quantity = Quantity(order.pair.base, base_size, order.path_id)
            base_wallet -= quantity
        except InsufficientFundsForAllocation:
            balance = base_wallet.locked[order.path_id]
            quantity = Quantity(order.pair.base, balance.size, order.path_id)
            base_wallet -= quantity

        quote_size = (order.price / price) * (quantity.size / price)
        quote_wallet += Quantity(order.pair.quote, quote_size, order.path_id)

        trade = Trade(order_id=order.id,
                      exchange_id=self.id,
                      step=self.clock.step,
                      pair=order.pair,
                      side=TradeSide.BUY,
                      trade_type=order.type,
                      quantity=quantity,
                      price=price,
                      commission=commission)

        # self._slippage_model.adjust_trade(trade)

        return trade
Exemplo n.º 15
0
def test_invalid_isub():

    # Add to balance with locked path_id
    wallet = Wallet(exchange, 10000 * USD)
    wallet.deposit(quantity=Quantity(USD, 500, path_id=path_id), reason="test")
    wallet.deposit(quantity=Quantity(USD, 700, path_id=other_id),
                   reason="test")

    with pytest.raises(InsufficientFunds):
        wallet.withdraw(quantity=11000 * USD, reason="test")

    with pytest.raises(InsufficientFunds):
        wallet.withdraw(quantity=Quantity(USD, 750, path_id), reason="test")

    with pytest.raises(InsufficientFunds):
        wallet.withdraw(quantity=Quantity(USD, 750, path_id), reason="test")

    with pytest.raises(IncompatibleInstrumentOperation):
        wallet.withdraw(quantity=500 * BTC, reason="test")
Exemplo n.º 16
0
def execute_buy_order(order: 'Order',
                      base_wallet: 'Wallet',
                      quote_wallet: 'Wallet',
                      current_price: float,
                      options: 'ExchangeOptions',
                      exchange_id: str,
                      clock: 'Clock') -> 'Trade':
    price = contain_price(current_price, options)

    if order.type == TradeType.LIMIT and order.price < current_price:
        return None

    commission = Quantity(order.pair.base, order.size * options.commission, order.path_id)
    size = contain_size(order.size - commission.size, options)

    if order.type == TradeType.MARKET:
        scale = order.price / price
        size = contain_size(scale * order.size - commission.size, options)

    base_wallet -= commission

    try:
        quantity = Quantity(order.pair.base, size, order.path_id)
        base_wallet -= quantity
    except InsufficientFunds:
        balance = base_wallet.locked[order.path_id]
        quantity = Quantity(order.pair.base, balance.size, order.path_id)
        base_wallet -= quantity

    quote_size = (order.price / price) * (size / price)
    quote_wallet += Quantity(order.pair.quote, quote_size, order.path_id)

    trade = Trade(order_id=order.id,
                  exchange_id=exchange_id,
                  step=clock.step,
                  pair=order.pair,
                  side=TradeSide.BUY,
                  trade_type=order.type,
                  quantity=quantity,
                  price=price,
                  commission=commission)

    return trade
Exemplo n.º 17
0
def test_valid_isub():

    # Add to remove from unlocked balance
    wallet = Wallet(exchange, 10000 * USD)
    wallet -= 500 * USD
    assert wallet.balance == 9500 * USD
    assert len(wallet.locked) == 0

    # Add to balance with locked path_id
    wallet = Wallet(exchange, 10000 * USD)
    wallet += Quantity(USD, 750, path_id=path_id)
    wallet += Quantity(USD, 1000, path_id=other_id)

    wallet -= Quantity(USD, 500, path_id=path_id)
    assert wallet.balance == 10000 * USD
    assert wallet.locked[path_id] == 250 * USD

    wallet -= Quantity(USD, 500, path_id=other_id)
    assert wallet.balance == 10000 * USD
    assert wallet.locked[other_id] == 500 * USD
Exemplo n.º 18
0
def test_invalid_truediv():
    # Price with different trading pairs
    p1 = Price(50, USD / BTC)
    p2 = Price(50, BTC / USD)
    with pytest.raises(IncompatibleTradingPairOperation):
        p1 / p2

    # Quantity with instrument different than the quote
    p1 = Price(50, USD / BTC)
    p2 = Quantity(USD, 50)
    with pytest.raises(IncompatiblePriceQuantityOperation):
        p1 / p2
Exemplo n.º 19
0
def test_valid_mul():
    # Price
    p1 = Price(50, USD / BTC)
    p2 = Price(5, USD / BTC)
    p = p1 * p2
    assert p.rate == 250
    assert p.pair == USD / BTC

    # Quantity
    p = Price(50, USD / BTC)
    size = Quantity(BTC, 5)
    q = p * size
    assert isinstance(q, Quantity)
    assert q.size == 250
    assert q.instrument == USD

    # Quantity with Path ID
    p = Price(50, USD / BTC)
    size = Quantity(BTC, 5, path_id="fake_id")
    q = p * size
    assert isinstance(q, Quantity)
    assert q.size == 250
    assert q.instrument == USD
    assert q.path_id == "fake_id"

    # int
    p1 = Price(50, USD/BTC)
    p2 = 5
    p = p1 * p2
    assert p.rate == 250
    assert p.pair == USD / BTC

    # float
    p1 = Price(50, USD / BTC)
    p2 = 5.0
    p = p1 * p2
    assert p.rate == 250
    assert p.pair == USD / BTC
Exemplo n.º 20
0
def test_valid_isub():

    # Add to remove from unlocked balance
    wallet = Wallet(exchange, 10000 * USD)
    wallet.withdraw(quantity=500 * USD, reason="test")
    assert wallet.balance == 9500 * USD
    assert len(wallet.locked) == 0

    # Add to balance with locked path_id
    wallet = Wallet(exchange, 10000 * USD)
    wallet.deposit(quantity=Quantity(USD, 750, path_id=path_id), reason="test")
    wallet.deposit(quantity=Quantity(USD, 1000, path_id=other_id),
                   reason="test")

    wallet.withdraw(quantity=Quantity(USD, 500, path_id=path_id),
                    reason="test")
    assert wallet.balance == 10000 * USD
    assert wallet.locked[path_id] == 250 * USD

    wallet.withdraw(quantity=Quantity(USD, 500, path_id=other_id),
                    reason="test")
    assert wallet.balance == 10000 * USD
    assert wallet.locked[other_id] == 500 * USD
Exemplo n.º 21
0
def test_valid_iadd():

    # Add to free unlocked balance
    wallet = Wallet(exchange, 10000 * USD)
    wallet += 500 * USD
    assert wallet.balance == 10500 * USD
    assert len(wallet.locked) == 0

    # Add to balance with locked path_id
    wallet = Wallet(exchange, 10000 * USD)
    wallet += Quantity(USD, 500, path_id=path_id)
    assert wallet.balance == 10000 * USD
    assert wallet.locked[path_id] == 500 * USD

    # Add to more balance with locked path_id
    wallet += Quantity(USD, 500, path_id=path_id)
    assert wallet.balance == 10000 * USD
    assert wallet.locked[path_id] == 1000 * USD

    # Add to balance that has another locked path_id
    wallet += Quantity(USD, 500, path_id=other_id)
    assert wallet.balance == 10000 * USD
    assert wallet.locked[path_id] == 1000 * USD
    assert wallet.locked[other_id] == 500 * USD
Exemplo n.º 22
0
def test_create_from_buy_order(mock_order_class,
                               mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.id = "fake_id"

    wallets = [Wallet(exchange, 10000.00*USD), Wallet(exchange, 2*BTC)]
    portfolio = Portfolio(USD, wallets)

    order = mock_order_class.return_value
    order.portfolio = portfolio
    order.path_id = "fake_path_id"
    order.price = 7000.00

    wallet_btc = portfolio.get_wallet(exchange.id, BTC)
    wallet_btc -= 0.4*BTC
    wallet_btc += Quantity(BTC, 0.4, path_id=order.path_id)

    assert wallet_btc.balance == 1.6 * BTC
    assert wallet_btc.locked[order.path_id].size == 0.4 * BTC

    order_spec = OrderSpec(
        side=TradeSide.SELL,
        trade_type=TradeType.MARKET,
        pair=USD/BTC
    )

    next_order = order_spec.create_order(order, exchange)
    assert next_order

    assert next_order.side == TradeSide.SELL
    assert next_order.type == TradeType.MARKET
    assert next_order.pair == USD/BTC
    assert next_order.path_id == order.path_id
    assert next_order.quantity.path_id == order.path_id
    assert next_order.quantity.instrument == BTC
Exemplo n.º 23
0
def test_create_from_sell_order(mock_order_class,
                                mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.id = "fake_id"

    wallets = [Wallet(exchange, 10000.00*USD), Wallet(exchange, 2*BTC)]
    portfolio = Portfolio(USD, wallets)

    order = mock_order_class.return_value
    order.portfolio = portfolio
    order.path_id = "fake_path_id"
    order.price = 7000.00

    wallet_usd = portfolio.get_wallet(exchange.id, USD)
    wallet_usd -= 1000*USD
    wallet_usd += Quantity(USD, 1000, path_id=order.path_id)

    assert wallet_usd.balance == 9000 * USD
    assert wallet_usd.locked[order.path_id].size == 1000 * USD

    order_spec = OrderSpec(
        side=TradeSide.BUY,
        trade_type=TradeType.MARKET,
        pair=USD/BTC
    )

    next_order = order_spec.create_order(order, exchange)
    assert next_order

    assert next_order.side == TradeSide.BUY
    assert next_order.type == TradeType.MARKET
    assert next_order.pair == USD/BTC
    assert next_order.path_id == order.path_id
    assert next_order.quantity.path_id == order.path_id
    assert next_order.quantity.instrument == USD
Exemplo n.º 24
0
 def from_tuple(cls, wallet_tuple: Tuple['Exchange', 'Instrument', float]):
     exchange, instrument, balance = wallet_tuple
     return cls(exchange, Quantity(instrument, balance))
Exemplo n.º 25
0
def test_on_fill_with_complex_order(mock_trade_class, mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.id = "fake_exchange_id"

    broker = Broker(exchange)

    wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)]
    portfolio = Portfolio(USD, wallets)

    side = TradeSide.BUY

    order = Order(step=0,
                  side=TradeSide.BUY,
                  trade_type=TradeType.MARKET,
                  pair=USD / BTC,
                  quantity=5200.00 * USD,
                  portfolio=portfolio,
                  price=7000.00)

    risk_criteria = Stop("down", 0.03) ^ Stop("up", 0.02)

    risk_management = OrderSpec(
        side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY,
        trade_type=TradeType.MARKET,
        pair=USD / BTC,
        criteria=risk_criteria)

    order += risk_management

    order.attach(broker)
    order.execute(exchange)

    broker._executed[order.id] = order

    # Execute fake trade
    price = 7000.00
    scale = order.price / price
    commission = 3.00 * USD

    base_size = scale * order.size - commission.size

    trade = mock_trade_class.return_value
    trade.order_id = order.id
    trade.size = base_size
    trade.price = price
    trade.commission = commission

    base_wallet = portfolio.get_wallet(exchange.id, USD)
    quote_wallet = portfolio.get_wallet(exchange.id, BTC)

    base_size = trade.size + trade.commission.size
    quote_size = (order.price / trade.price) * (trade.size / trade.price)

    base_wallet -= Quantity(USD, size=base_size, path_id=order.path_id)
    quote_wallet += Quantity(BTC, size=quote_size, path_id=order.path_id)

    assert trade.order_id in broker.executed.keys()
    assert trade not in broker.trades
    assert broker.unexecuted == []

    order.fill(exchange, trade)

    assert order.remaining_size == 0
    assert trade in broker.trades[order.id]
    assert broker.unexecuted != []
Exemplo n.º 26
0
def execute_sell_order(order: 'Order', base_wallet: 'Wallet',
                       quote_wallet: 'Wallet', current_price: float,
                       options: 'ExchangeOptions', exchange_id: str,
                       clock: 'Clock') -> 'Trade':
    price = contain_price(current_price, options)

    if order.type == TradeType.LIMIT and order.price > current_price:
        return None

    commission = Quantity(order.pair.base, order.size * options.commission,
                          order.path_id)
    size = contain_size(order.size - commission.size, options)

    try:
        quote_size = (size / price) * (price / order.price)
        quote_quantity = Quantity(order.pair.quote, quote_size, order.path_id)
        quote_wallet -= quote_quantity.reason(
            "REMOVE FROM LOCKED TO FILL ORDER")
    except InsufficientFunds:
        balance = quote_wallet.locked[order.path_id]
        quote_size = balance.size
        remove_quantity = Quantity(order.pair.quote, quote_size, order.path_id)
        quote_wallet -= remove_quantity.reason(
            "REMOVE FROM LOCKED TO FILL ORDER (INSUFFICIENT FUNDS)")

    base_size = (quote_size * price) / (price / order.price)
    quantity = Quantity(order.pair.base, base_size, order.path_id)

    base_wallet += quantity.reason("SOLD @ {} {}".format(price, order.pair))
    base_wallet -= commission.reason("COMMISSION FOR SELL")

    trade = Trade(order_id=order.id,
                  exchange_id=exchange_id,
                  step=clock.step,
                  pair=order.pair,
                  side=TradeSide.SELL,
                  trade_type=order.type,
                  quantity=quantity,
                  price=price,
                  commission=commission)

    return trade
Exemplo n.º 27
0
 def reset(self):
     self._balance = Quantity(self._instrument, self._initial_size)
     self._locked = {}
Exemplo n.º 28
0
def test_on_fill_with_complex_order(mock_trade_class, mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options.max_trade_size = 1e6
    exchange.id = "fake_exchange_id"
    exchange.name = "coinbase"
    exchange.quote_price = lambda pair: Decimal(7000.00)

    broker = Broker()
    broker.exchanges = [exchange]

    wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)]
    portfolio = Portfolio(USD, wallets)

    side = TradeSide.BUY

    order = Order(step=0,
                  exchange_pair=ExchangePair(exchange, USD / BTC),
                  side=TradeSide.BUY,
                  trade_type=TradeType.MARKET,
                  quantity=5200.00 * USD,
                  portfolio=portfolio,
                  price=Decimal(7000.00))

    risk_criteria = Stop("down", 0.03) ^ Stop("up", 0.02)

    risk_management = OrderSpec(
        side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY,
        trade_type=TradeType.MARKET,
        exchange_pair=ExchangePair(exchange, USD / BTC),
        criteria=risk_criteria)

    order += risk_management

    order.attach(broker)
    order.execute()

    broker._executed[order.id] = order

    # Execute fake trade
    price = Decimal(7000.00)
    scale = order.price / price
    commission = 3.00 * USD

    base_size = scale * order.size - commission.size

    trade = mock_trade_class.return_value
    trade.order_id = order.id
    trade.size = base_size
    trade.quantity = base_size * USD
    trade.price = price
    trade.commission = commission

    base_wallet = portfolio.get_wallet(exchange.id, USD)
    quote_wallet = portfolio.get_wallet(exchange.id, BTC)

    base_size = trade.size + trade.commission.size
    quote_size = (order.price / trade.price) * (trade.size / trade.price)

    base_wallet.withdraw(quantity=Quantity(USD,
                                           size=base_size,
                                           path_id=order.path_id),
                         reason="test")
    quote_wallet.deposit(quantity=Quantity(BTC,
                                           size=quote_size,
                                           path_id=order.path_id),
                         reason="test")

    assert trade.order_id in broker.executed.keys()
    assert trade not in broker.trades
    assert broker.unexecuted == []

    order.fill(trade)

    assert order.remaining == 0
    assert trade in broker.trades[order.id]
    assert broker.unexecuted != []
Exemplo n.º 29
0
def test_invalid_rmul():
    # Quantity with instrument different than the quote
    p1 = Quantity(USD, 50)
    p2 = Price(50, USD / BTC)
    with pytest.raises(IncompatiblePriceQuantityOperation):
        p1 * p2
Exemplo n.º 30
0
    def transfer(source: 'Wallet',
                 target: 'Wallet',
                 quantity: 'Quantity',
                 commission: 'Quantity',
                 exchange_pair: 'ExchangePair',
                 reason: str):
        """
        Parameters
        ----------
            source : 'Wallet'
                The wallet in which funds will be transferred from
            target : 'Wallet'
                The wallet in which funds will be transferred to
            quantity : 'Quantity'
                The quantity to be transferred from the source to the target.
                In terms of the instrument of the source wallet.
            commission :  'Quantity'
                The commission to be taken from the source wallet for performing
                the transfer of funds.
            exchange_pair : 'ExchangePair'
                The exchange pair associated with the transfer
        """
        quantity = quantity.quantize()
        commission = commission.quantize()

        pair = source.instrument / target.instrument
        poid = quantity.path_id

        lsb1 = source.locked.get(poid).size
        ltb1 = target.locked.get(poid, 0 * pair.quote).size

        commission = source.withdraw(commission, "COMMISSION")
        quantity = source.withdraw(quantity, "FILL ORDER")

        if quantity.instrument == exchange_pair.pair.base:
            instrument = exchange_pair.pair.quote
            converted_size = quantity.size / exchange_pair.price
        else:
            instrument = exchange_pair.pair.base
            converted_size = quantity.size * exchange_pair.price

        converted = Quantity(instrument, converted_size, quantity.path_id).quantize()

        converted = target.deposit(converted, 'TRADED {} {} @ {}'.format(quantity,
                                                                         exchange_pair,
                                                                         exchange_pair.price))

        lsb2 = source.locked.get(poid).size
        ltb2 = target.locked.get(poid, 0 * pair.quote).size

        q = quantity.size
        c = commission.size
        cv = converted.size
        p = exchange_pair.inverse_price if pair == exchange_pair.pair else exchange_pair.price

        source_quantization = Decimal(10) ** -source.instrument.precision
        target_quantization = Decimal(10) ** -target.instrument.precision

        lhs = Decimal((lsb1 - lsb2) - (q + c)).quantize(source_quantization)
        rhs = Decimal(ltb2 - ltb1 - cv).quantize(target_quantization)

        lhs_eq_zero = np.isclose(float(lhs), 0, atol=float(source_quantization))
        rhs_eq_zero = np.isclose(float(rhs), 0, atol=float(target_quantization))

        if not lhs_eq_zero or not rhs_eq_zero:
            equation = "({} - {}) - ({} + {}) != ({} - {}) - {}   [LHS = {}, RHS = {}, Price = {}]".format(
                lsb1, lsb2, q, c, ltb2, ltb1, cv, lhs, rhs, p
            )

            raise Exception("Invalid Transfer: " + equation)

        return Transfer(quantity, commission, exchange_pair.price)