Example #1
0
def test_to_dict(mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "coinbase"
    exchange.clock = mock.Mock()
    exchange.clock.step = 0
    exchange.quote_price = mock.Mock(return_value=Decimal(7000.00))

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

    d = order_spec.to_dict()
    assert d == {
        "id": order_spec.id,
        "type": order_spec.type,
        "exchange_pair": order_spec.exchange_pair,
        "criteria": order_spec.criteria
    }

    order_spec = OrderSpec(side=TradeSide.BUY,
                           trade_type=TradeType.MARKET,
                           exchange_pair=ExchangePair(exchange, USD / BTC),
                           criteria=lambda order, exchange: True)

    d = order_spec.to_dict()
    assert d == {
        "id": order_spec.id,
        "type": order_spec.type,
        "exchange_pair": order_spec.exchange_pair,
        "criteria": order_spec.criteria
    }
Example #2
0
def test_init(mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "coinbase"
    exchange.clock = mock.Mock()
    exchange.clock.step = 0

    side = TradeSide.BUY
    trade_type = TradeType.MARKET

    # Create order specification without criteria
    order_spec = OrderSpec(side=side,
                           trade_type=trade_type,
                           exchange_pair=ExchangePair(exchange, USD / BTC))

    assert order_spec.id
    assert order_spec.side == side
    assert order_spec.type == trade_type
    assert order_spec.exchange_pair == ExchangePair(exchange, USD / BTC)
    assert not order_spec.criteria

    # Create order specification with criteria
    order_spec = OrderSpec(side=side,
                           trade_type=trade_type,
                           exchange_pair=ExchangePair(exchange, USD / BTC),
                           criteria=lambda order, exchange: True)

    assert order_spec.id
    assert order_spec.side == side
    assert order_spec.type == trade_type
    assert order_spec.exchange_pair == ExchangePair(exchange, USD / BTC)
    assert order_spec.criteria
Example #3
0
def test_on_cancel(mock_exchange_class, cancel_listener):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "bitfinex"
    exchange.clock = mock.Mock()
    exchange.clock.step = 0
    exchange.quote_price = mock.Mock(return_value=Decimal(7000.00))

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

    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))

    order.attach(cancel_listener)

    assert not cancel_listener.listened
    order.cancel()
    assert cancel_listener.listened
Example #4
0
def test_on_complete(mock_trade_class, mock_exchange_class, complete_listener):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "bitfinex"
    exchange.clock = mock.Mock()
    exchange.clock.step = 0
    exchange.quote_price = mock.Mock(return_value=Decimal(7000.00))

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

    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))

    order.attach(complete_listener)

    order.execute()

    trade = mock_trade_class.return_value
    trade.size = Decimal(5197.00)
    trade.quantity = trade.size * USD
    trade.commission = 3.00 * USD

    order.fill(trade)

    assert not complete_listener.listened
    order.complete()
    assert complete_listener.listened
Example #5
0
def test_transfer():

    exchange = mock.Mock()
    price = Decimal(9750.19).quantize(Decimal(10)**-2)
    exchange.quote_price = lambda pair: price
    exchange.name = "bitfinex"

    order = mock.Mock()
    order.path_id = "fake_id"

    exchange_pair = ExchangePair(exchange, USD / BTC)

    source = Wallet(exchange, 18903.89 * USD)
    source.lock(917.07 * USD, order, "test")

    target = Wallet(exchange, 3.79283997 * BTC)

    quantity = (256.19 * USD).lock_for("fake_id")
    commission = (2.99 * USD).lock_for("fake_id")

    Wallet.transfer(source, target, quantity, commission, exchange_pair,
                    "transfer")

    source = Wallet(exchange, 3.79283997 * BTC)
    source.lock(3.00000029 * BTC, order, "test")

    target = Wallet(exchange, 18903.89 * USD)

    quantity = (2.19935873 * BTC).lock_for("fake_id")
    commission = (0.00659732 * BTC).lock_for("fake_id")

    Wallet.transfer(source, target, quantity, commission, exchange_pair,
                    "transfer")
Example #6
0
def test_str(mock_exchange):
    exchange = mock_exchange.return_value
    exchange.name = "coinbase"

    exchange_pair = ExchangePair(exchange, USD/BTC)

    assert str(exchange_pair) == "coinbase:USD/BTC"
Example #7
0
def test_str(mock_exchange):
    exchange = mock_exchange.return_value
    exchange.name = "bitfinex"

    exchange_pair = ExchangePair(exchange, USD/BTC)

    assert str(exchange_pair) == "bitfinex:USD/BTC"
Example #8
0
def test_valid_init(mock_exchange):

    exchange = mock_exchange.return_value
    exchange.name = "coinbase"

    exchange_pair = ExchangePair(exchange, USD/BTC)
    assert exchange_pair
    assert exchange_pair.pair.base == USD
    assert exchange_pair.pair.quote == BTC
Example #9
0
def test_create_from_buy_order(mock_order_class,
                               mock_exchange_class):
    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "bitfinex"
    exchange.clock = mock.Mock()
    exchange.clock.step = 0
    exchange.quote_price = mock.Mock(return_value=Decimal(7000.00))

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

    order = mock_order_class.return_value
    order.portfolio = portfolio
    order.exchange_pair = ExchangePair(exchange, USD / BTC)
    order.path_id = "fake_path_id"
    order.price = Decimal(7000.00)

    wallet_btc = portfolio.get_wallet(exchange.id, BTC)
    wallet_btc.lock(
        quantity=0.4 * BTC,
        order=order,
        reason="test"
    )

    assert float(wallet_btc.balance.size) == 1.6
    assert float(wallet_btc.locked[order.path_id].size) == 0.4

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

    next_order = order_spec.create_order(order)
    assert next_order

    assert next_order.side == TradeSide.SELL
    assert next_order.type == TradeType.MARKET
    assert next_order.exchange_pair == ExchangePair(exchange, 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
Example #10
0
 def exchange_pairs(self) -> 'List[ExchangePair]':
     """All the exchange pairs in the portfolio. (`List[ExchangePair]`, read-only)"""
     exchange_pairs = []
     for w in self.wallets:
         if w.instrument != self.base_instrument:
             exchange_pairs += [
                 ExchangePair(w.exchange,
                              self.base_instrument / w.instrument)
             ]
     return exchange_pairs
Example #11
0
def test_str(mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "coinbase"
    exchange.clock = mock.Mock()
    exchange.clock.step = 0
    exchange.quote_price = mock.Mock(return_value=Decimal(7000.00))

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

    pattern = re.compile("<[A-Z][a-zA-Z]*:\\s(\\w+=.*,\\s)*(\\w+=.*)>")

    string = str(order_spec)
    assert string

    assert string == pattern.fullmatch(string).string
Example #12
0
def test_on_fill(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 = "bitfinex"
    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)

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

    order.attach(broker)

    order.execute()

    broker.executed[order.id] = order

    trade = mock_trade_class.return_value
    trade.quantity = 5197.00 * USD
    trade.commission = 3.00 * USD
    trade.order_id = order.id

    assert order.status == OrderStatus.OPEN
    order.fill(trade)
    assert order.status == OrderStatus.FILLED

    assert order.remaining == 0

    assert trade in broker.trades[order.id]
Example #13
0
def assert_execute_order(current_price,
                         base_balance,
                         quote_balance,
                         order_side,
                         order_quantity,
                         order_price,
                         ):
    mock_clock = mock.Mock()
    clock = mock_clock.return_value
    clock.step = 3

    base = base_balance.instrument
    quote = quote_balance.instrument

    current_price = Decimal(current_price).quantize(Decimal(10) ** -base.precision)
    order_price = Decimal(order_price).quantize(Decimal(10) ** -base.precision)

    options = ExchangeOptions()
    mock_exchange = mock.Mock()
    exchange = mock_exchange.return_value
    exchange.name = "coinbase"
    exchange.options = options
    exchange.quote_price = lambda pair: current_price

    base_wallet = Wallet(exchange, base_balance)
    quote_wallet = Wallet(exchange, quote_balance)

    portfolio = Portfolio(USD, [
        base_wallet,
        quote_wallet
    ])

    order = Order(
        step=1,
        side=order_side,
        trade_type=TradeType.MARKET,
        exchange_pair=ExchangePair(exchange, base/quote),
        quantity=order_quantity,
        portfolio=portfolio,
        price=order_price,
        path_id="fake_id"
    )
    order.status = OrderStatus.OPEN

    if order_side == TradeSide.BUY:

        trade = execute_buy_order(
            order,
            base_wallet,
            quote_wallet,
            current_price=current_price,
            options=options,
            clock=clock,
        )

        base_balance = base_wallet.locked['fake_id'].size
        quote_balance = quote_wallet.locked['fake_id'].size

        expected_base_balance = order_quantity.size - (trade.size + trade.commission.size)
        expected_quote_balance = trade.size / current_price

        expected_base_balance = expected_base_balance.quantize(Decimal(10) ** -base.precision)
        expected_quote_balance = expected_quote_balance.quantize(Decimal(10) ** -quote.precision)

        assert base_balance == expected_base_balance
        assert quote_balance == expected_quote_balance

    else:
        trade = execute_sell_order(
            order,
            base_wallet,
            quote_wallet,
            current_price=current_price,
            options=options,
            clock=clock,
        )

        base_balance = base_wallet.locked['fake_id'].size
        quote_balance = quote_wallet.locked['fake_id'].size

        expected_base_balance = trade.size * current_price
        expected_base_balance = expected_base_balance.quantize(Decimal(10)**-base.precision)

        assert base_balance == expected_base_balance
        assert quote_balance == 0
Example #14
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 = "bitfinex"
    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.add_order_spec(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 != []
Example #15
0
def proportion_order(portfolio: 'Portfolio', source: 'Wallet',
                     target: 'Wallet', proportion: float) -> 'Order':
    """Creates an order that sends a proportion of funds from one wallet to
    another.

    Parameters
    ----------
    portfolio : `Portfolio`
        The portfolio that contains both wallets.
    source : `Wallet`
        The source wallet for the funds.
    target : `Wallet`
        The target wallet for the funds.
    proportion : float
        The proportion of funds to send.
    """
    assert 0.0 < proportion <= 1.0
    exchange = source.exchange

    base_params = {
        'step': portfolio.clock.step,
        'portfolio': portfolio,
        'trade_type': TradeType.MARKET,
        'start': portfolio.clock.step,
        'end': portfolio.clock.step + 1
    }
    pair = None

    is_source_base = (source.instrument == portfolio.base_instrument)
    is_target_base = (target.instrument == portfolio.base_instrument)

    if is_source_base or is_target_base:

        if is_source_base:
            pair = source.instrument / target.instrument
        else:
            pair = target.instrument / source.instrument

        exchange_pair = ExchangePair(exchange, pair)

        balance = source.balance.as_float()
        size = min(balance * proportion, balance)
        quantity = (size * source.instrument).quantize()

        params = {
            **base_params, 'side':
            TradeSide.BUY if is_source_base else TradeSide.SELL,
            'exchange_pair': exchange_pair,
            'price': exchange_pair.price,
            'quantity': quantity
        }

        return Order(**params)

    pair = portfolio.base_instrument / source.instrument
    exchange_pair = ExchangePair(exchange, pair)

    balance = source.balance.as_float()
    size = min(balance * proportion, balance)
    quantity = (size * source.instrument).quantize()

    params = {
        **base_params, 'side': TradeSide.SELL,
        'exchange_pair': exchange_pair,
        'price': exchange_pair.price,
        'quantity': quantity
    }

    order = Order(**params)

    pair = portfolio.base_instrument / target.instrument

    order.add_order_spec(
        OrderSpec(side=TradeSide.BUY,
                  trade_type=TradeType.MARKET,
                  exchange_pair=ExchangePair(exchange, pair),
                  criteria=None))
    return order