예제 #1
0
    def test_position_delta_with_btc_fees(self):
        self.bid.fee = Money('0.01', 'BTC')
        self.ask.fee = Money('0.02', 'BTC')

        position = positions.position_delta(self.trades)

        position['BTC'].should.equal(Money('0', 'BTC'))
        position['fiat'].should.equal(Money('-7.5', 'USD'))
예제 #2
0
def get_pl_from_open_orders(position_trades, exchange_name, open_orders):
    """
    Given our current position, and the open orders on an exchange, what would our
    realized p&l be if a market order came in and consumed our order entirely?

    Details: we naively assume that our order is sized such that it would completely
    close our position. If there is no open order on that exchange, we return None.
    """

    bids = open_orders['bids']
    asks = open_orders['asks']

    pl = Money('0', 'USD')

    open_position = positions.position_delta(position_trades)
    unmatched_fees = revenue_lib.all_fees(position_trades)[0].to('USD')

    fiat_position = open_position['fiat'].to('USD')
    btc_position = open_position['BTC']

    value_of_btc = Money(0, 'USD')

    if btc_position > 0 and len(asks) > 0:
        close_order = asks[
            0]  # Naively assume the first order is what we care about.

        close_price = Money(close_order[0], 'USD')

        value_of_btc = close_price * btc_position.amount
    elif btc_position <= 0 and len(bids) > 0:
        close_order = bids[0]

        close_price = Money(close_order[0], 'USD')

        value_of_btc = close_price * btc_position.amount
    else:
        return Money(0, 'USD'), Money(0, 'USD')

    revenue = fiat_position + unmatched_fees + value_of_btc.to('USD')

    exchange = exchange_factory.make_exchange_from_key(exchange_name)
    new_fee = exchange.limit_order_fee * abs(value_of_btc.to('USD'))

    fees = unmatched_fees + new_fee

    return revenue, fees
예제 #3
0
def get_pl_from_limit_order(position_trades, orderbook, exchange_name):
    """
    Given our current position and an exchange orderbook, what would our realized p&l
    be on that position if we were the top order on this exchange, in the amount and
    side that would exactly close our position, and a market order came through and took
    the whole order?
    """
    pl = Money('0', 'USD')

    open_position = positions.position_delta(position_trades)
    unmatched_fees = revenue_lib.all_fees(position_trades)[0].to('USD')

    fiat_position = open_position['fiat'].to('USD')
    btc_position = open_position['BTC']

    value_of_btc = Money(0, 'USD')

    if btc_position > 0:
        # Then we're in a long position, we want to sell, so place an order in front
        # of the top ask.
        top_ask = orderbook['asks'][0]

        close_price = top_ask.price - Money('0.01', top_ask.price.currency)

        value_of_btc = close_price * btc_position.amount
    else:
        # Then we're in a long position, we want to sell, so place an order in front
        # of the top bid.
        top_bid = orderbook['bids'][0]

        close_price = top_bid.price + Money('0.01', top_bid.price.currency)

        value_of_btc = close_price * btc_position.amount

    revenue = fiat_position + unmatched_fees + value_of_btc.to('USD')

    exchange = exchange_factory.make_exchange_from_key(exchange_name)
    new_fee = exchange.market_order_fee * abs(value_of_btc.to('USD'))

    fees = unmatched_fees + new_fee

    return revenue, fees
예제 #4
0
def realized_pl(matched_trades, price_currency=None, volume_currency='BTC'):
    """
    Take a matched_trades object and return our realized profit in the price currency
    over those trades. We do this with the insight that for a matched_trades object,
    the position_delta in the volume currency will be zero, and the position delta in
    the price currency will be our realized profit.
    """

    realized_position = positions.position_delta(
        matched_trades,
        price_currency,
        volume_currency,
    )

    if realized_position[volume_currency] != Money('0', volume_currency):
        raise ValueError('Matched Trades must sum up to 0 %s' %
                         volume_currency)

    realized_pl = realized_position['fiat']

    return realized_pl
예제 #5
0
    def get_current_trading_result(self, matched_trades, position_trades, currency, fundamental_value=None):
        profit, revenue, fees, volume_currency_fees = revenue_lib.profit_data(
            matched_trades,
            currency,
            volume_currency=self.volume_currency,
        )

        if fundamental_value:
            open_pl = revenue_lib.open_pl(
                position_trades,
                fundamental_value,
                price_currency=currency,
                volume_currency=self.volume_currency,
            )
        else:
            open_pl = None

        open_position = positions.position_delta(
            position_trades,
            volume_currency=self.volume_currency,
        )[self.volume_currency]

        return profit, revenue, fees, volume_currency_fees, open_pl, open_position
예제 #6
0
def get_pl_from_market_order(position_trades, orderbook, exchange_name):
    """
    Given our current position and an exchange orderbook, what would our realized p&l
    be if we closed that position right now with a market order?
    """
    pl = Money('0', 'USD')

    open_position = positions.position_delta(position_trades)
    unmatched_fees = revenue_lib.all_fees(position_trades)[0].to('USD')

    fiat_position = open_position['fiat'].to('USD')
    btc_position = open_position['BTC']

    value_of_btc = Money(0, 'BTC')

    if btc_position > 0:
        value_of_btc = quote_lib.price_quote_from_orderbook(
            orderbook,
            Order.ASK,
            btc_position,
        )['total_price']
    else:
        value_of_btc = quote_lib.price_quote_from_orderbook(
            orderbook,
            Order.BID,
            btc_position,
        )['total_price']

    revenue = fiat_position + unmatched_fees + value_of_btc.to('USD')

    exchange = exchange_factory.make_exchange_from_key(exchange_name)
    new_fee = exchange.market_order_fee * abs(value_of_btc.to('USD'))

    fees = unmatched_fees + new_fee

    return revenue, fees
예제 #7
0
    def test_position_delta(self):
        position = positions.position_delta(self.trades)

        position['BTC'].should.equal(Money('0', 'BTC'))
        position['fiat'].should.equal(Money('0', 'USD'))
예제 #8
0
def split_trades(trades, price_currency='USD', volume_currency='BTC'):
    """
    This function creates the matched_trades and position_trades objects. Matched_trades
    is a list of pairs of semi-real trades, in which the first fake-trade represents a
    chunk of a real trade that opened a position, and the second fake-trade represents
    the chunk of another real trade that closed the first position. In this way the pair
    represents a complete loop of an open-and-closing of a position. This structure is
    very useful for several purposes.
    """

    # This is slow but safer for now, don't want to modify original array.
    trades_copy = []

    for t in trades:
        # We don't need orders here, so we could probaby use SimpleTrade.
        tc = copy_trade(t)
        trades_copy.append(tc)

    trades = trades_copy
    trades.sort(key=lambda t: t.time_created)

    total_volume = sum([t.volume for t in trades])
    total_price = sum([t.price_in_currency(price_currency) for t in trades])

    bids = []
    asks = []

    for t in trades:
        if t.trade_type == Consts.BID:
            bids.append(t)
        else:
            asks.append(t)

    matched_trades = []

    while bids and asks:
        if bids[0].volume < asks[0].volume:
            active = bids.pop(0)
            trades_to_match = asks
        else:
            active = asks.pop(0)
            trades_to_match = bids

        if active.volume > 0:
            matched_trades.append(active)

        volume_to_match = active.volume

        while volume_to_match > 0:
            match = trades_to_match[0]

            if match.volume <= volume_to_match:  # We totally match.
                volume_to_match -= match.volume
                match = trades_to_match.pop(0)  # Actually remove it.

                if match.volume > 0:
                    matched_trades.append(match)
            else:  # We match part of the opposite.
                orig_price = match.price
                orig_volume = match.volume

                # Split the partial match into 2 trades.
                fraction = volume_to_match / match.volume
                matched_partial_trade = copy_trade(match)
                matched_partial_trade.price = match.price * fraction
                matched_partial_trade.fee = match.fee * fraction
                matched_partial_trade.volume = volume_to_match

                old_fraction = (match.volume - volume_to_match) / match.volume
                match.price *= old_fraction
                match.fee *= old_fraction
                match.volume -= volume_to_match

                assert abs(match.price + matched_partial_trade.price -
                           orig_price) < 1e-10
                assert abs(match.volume + matched_partial_trade.volume -
                           orig_volume) < 1e-10

                if matched_partial_trade.volume > 0:
                    matched_trades.append(matched_partial_trade)

                volume_to_match = 0

    assert bids == [] or asks == []  # One should be empty.

    position_trades = bids + asks

    # Assert that our matched_trades are matched.
    matched_position = positions.position_delta(
        matched_trades,
        price_currency=price_currency,
        volume_currency=volume_currency,
    )

    assert matched_position[volume_currency] == Money('0', volume_currency)

    # Assert that our total price and volume haven't changed.
    new_total_volume = sum(
        [t.volume for t in (matched_trades + position_trades)])
    new_total_price = sum([
        t.price_in_currency(price_currency)
        for t in (matched_trades + position_trades)
    ])

    assert abs(new_total_volume - total_volume) < 1e-10, \
        "%s != %s" % (new_total_volume, total_volume)

    assert abs(new_total_price - total_price) < 1e-10, \
        "%s != %s" % (new_total_price, total_price)

    return matched_trades, position_trades