Exemple #1
0
def test_detach(mock_exchange_class, mock_order_listener_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

    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=5000.00 * USD,
                  portfolio=portfolio,
                  price=Decimal(7000.00))

    listener = mock_order_listener_class.return_value
    order.attach(listener)
    assert len(order.listeners) == 1
    assert listener in order.listeners

    order.detach(listener)
    assert len(order.listeners) == 0
    assert listener not in order.listeners
Exemple #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
Exemple #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
Exemple #4
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
    }
Exemple #5
0
def test_init(mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "coinbase"

    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=5000 * USD,
                  price=7000,
                  portfolio=portfolio)

    assert order
    assert order.id
    assert order.path_id
    assert order.step == 0
    assert order.quantity.instrument == USD
    assert order.remaining == order.quantity
    assert isinstance(order.pair, TradingPair)
    assert order.pair.base == USD
    assert order.pair.quote == BTC
Exemple #6
0
def test_iadd(mock_exchange_class, mock_order_spec_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))

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

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

    order_spec = mock_order_spec_class.return_value

    assert len(order._specs) == 0
    order.add_order_spec(order_spec)
    assert len(order._specs) == 1

    assert order_spec in order._specs
Exemple #7
0
def test_properties(mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_exchange_id"
    exchange.name = "coinbase"

    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.LIMIT,
                  quantity=5000.00 * USD,
                  portfolio=portfolio,
                  price=7000.00)

    assert order
    assert order.step == 0
    assert order.base_instrument == USD
    assert order.quote_instrument == BTC
    assert order.size == 5000.00 * USD
    assert order.price == 7000.00
    assert order.trades == []
    assert order.is_buy
    assert not order.is_sell
    assert not order.is_market_order
    assert order.is_limit_order
Exemple #8
0
def test_is_complete(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

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

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

    assert not order.is_complete

    order.remaining = 0 * USD
    assert order.is_complete
Exemple #9
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))

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

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

    string = str(order)
    assert string

    assert string == pattern.fullmatch(string).string
Exemple #10
0
def test_release(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))

    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.execute()

    wallet_usd = portfolio.get_wallet(exchange.id, USD)
    assert wallet_usd.balance == 4800 * USD
    assert wallet_usd.locked_balance == 5200 * USD
    assert order.path_id in wallet_usd.locked.keys()

    order.release()

    assert wallet_usd.balance == 10000 * USD
    assert wallet_usd.locked_balance == 0 * USD
    assert order.path_id not in wallet_usd.locked.keys()
Exemple #11
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
Exemple #12
0
def test_proportion_order_init(mock_exchange_class):

    exchange = mock_exchange_class.return_value
    exchange.options = ExchangeOptions()
    exchange.id = "fake_id"
    exchange.name = "fake_exchange"

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

    order = proportion_order(portfolio=portfolio,
                             source=wallet_usd,
                             target=wallet_btc,
                             proportion=1.0)

    assert order
Exemple #13
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
Exemple #14
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
Exemple #15
0
def test_complete_basic_order(mock_order_listener_class, mock_trade_class,
                              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

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

    listener = mock_order_listener_class.return_value
    listener.on_complete = mock.Mock(return_value=None)
    order.attach(listener)

    order.execute()

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

    order.fill(trade)

    assert order.status == OrderStatus.PARTIALLY_FILLED
    next_order = order.complete()
    assert order.status == OrderStatus.FILLED

    listener.on_complete.assert_called_once_with(order)
    assert not next_order
Exemple #16
0
def test_to_json(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))

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

    d = {
        "id": str(order.id),
        "step": int(order.step),
        "exchange_pair": str(order.exchange_pair),
        "status": str(order.status),
        "type": str(order.type),
        "side": str(order.side),
        "base_symbol": str(order.pair.base.symbol),
        "quote_symbol": str(order.pair.quote.symbol),
        "quantity": str(order.quantity),
        "size": float(order.size),
        "remaining": str(order.remaining),
        "price": float(order.price),
        "criteria": str(order.criteria),
        "path_id": str(order.path_id),
        "created_at": str(order.created_at)
    }

    assert order.to_json() == d
Exemple #17
0
def test_execute(mock_order_listener_class, 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

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

    listener = mock_order_listener_class.return_value
    listener.on_execute = mock.Mock(return_value=None)
    order.attach(listener)

    assert order.status == OrderStatus.PENDING
    order.execute()
    assert order.status == OrderStatus.OPEN

    wallet_usd = portfolio.get_wallet(exchange.id, USD)
    wallet_btc = portfolio.get_wallet(exchange.id, BTC)

    assert wallet_usd.balance == 4800 * USD
    assert wallet_usd.locked_balance == 5200 * USD
    assert order.path_id in wallet_usd.locked.keys()
    assert wallet_btc.balance == 0 * BTC

    listener.on_execute.assert_called_once_with(order)
Exemple #18
0
def test_cancel(mock_order_listener_class, mock_trade_class,
                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))

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

    listener = mock_order_listener_class.return_value
    listener.on_cancel = mock.Mock(return_value=None)
    order.attach(listener)

    order.execute()

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

    trade = mock_trade_class.return_value
    trade.size = Decimal(scale * order.size - commission.size)
    trade.quantity = trade.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 + 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")

    order.fill(trade)

    assert order.status == OrderStatus.PARTIALLY_FILLED
    assert base_wallet.balance == 4800.00 * USD
    assert float(round(base_wallet.locked[order.path_id].size, 2)) == 7.42
    assert quote_wallet.balance == 0 * BTC
    assert float(round(quote_wallet.locked[order.path_id].size,
                       8)) == 0.73925519
    order.cancel()

    listener.on_cancel.assert_called_once_with(order)
    assert float(round(base_wallet.balance.size, 2)) == 4807.42
    assert order.path_id not in base_wallet.locked
    assert float(round(quote_wallet.balance.size, 8)) == 0.73925519
    assert order.path_id not in quote_wallet.locked
Exemple #19
0
def test_complete_complex_order(mock_trade_class, 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))

    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.execute()

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

    base_size = scale * order.size - commission.size

    trade = mock_trade_class.return_value
    trade.size = Decimal(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")

    # Fill fake trade
    order.fill(trade)

    assert order.path_id in portfolio.get_wallet(exchange.id, USD).locked

    assert order.status == OrderStatus.PARTIALLY_FILLED
    next_order = order.complete()
    assert order.status == OrderStatus.FILLED

    assert next_order
    assert next_order.path_id == order.path_id
    assert next_order.size
    assert next_order.status == OrderStatus.PENDING
    assert next_order.side == TradeSide.SELL
    assert next_order.exchange_pair == ExchangePair(exchange, USD / BTC)
Exemple #20
0
def create_env(config, train="train"):
    cdd = CryptoDataDownload()
    data = cdd.fetch("Bitstamp", "USD", "BTC", "1h")
    if False:
        data.close = data.close / 20 + range(len(data))
        print("genenrating fake increase")
    if train == "train":
        data = data[0:int(len(data) / 2)]  # training
        print("using first half for training")
    elif train == "eval":
        data = data[int(len(data) / 2):]  # validation
        print("using second half for eval")
    else:
        print("using all data")

    pclose = Stream.source(list(data.close), dtype="float").rename("USD-BTC")
    pmin = Stream.source(list(data.low), dtype="float").rename("USD-BTClow")
    pmax = Stream.source(list(data.high), dtype="float").rename("USD-BTChigh")

    pmin = Stream.source(list(data.low), dtype="float").rename("USD-BTClow")
    pmax = Stream.source(list(data.high), dtype="float").rename("USD-BTChigh")

    pmin3 = pmin.rolling(window=3).min()
    pmin10 = pmin.rolling(window=10).min()
    pmin20 = pmin.rolling(window=20).min()
    pmax3 = pmax.rolling(window=3).max()
    pmax10 = pmax.rolling(window=10).max()
    pmax20 = pmax.rolling(window=20).max()

    eo = ExchangeOptions(commission=0.002)  #
    coinbase = Exchange("coinbase", service=execute_order, options=eo)(
        pclose
    )

    cash = Wallet(coinbase, 100000 * USD)
    asset = Wallet(coinbase, 0 * BTC)

    portfolio = Portfolio(USD, [
        cash,
        asset
    ])

    feed = DataFeed([

        (pclose.log() - pmin3.log()).fillna(0).rename("relmin3"),
        (pclose.log() - pmin10.log()).fillna(0).rename("relmin10"),
        (pclose.log() - pmin20.log()).fillna(0).rename("relmin20"),
        (pclose.log() - pmax3.log()).fillna(0).rename("relmax3"),
        (pclose.log() - pmax10.log()).fillna(0).rename("relmax10"),
        (pclose.log() - pmax20.log()).fillna(0).rename("relmax20"),

    ])

    action_scheme = BSH(cash=cash, asset=asset)

    renderer_feed = DataFeed([
        Stream.source(list(data.close), dtype="float").rename("price"),
        Stream.sensor(action_scheme, lambda s: s.action, dtype="float").rename("action")  # only works for BSH
    ])

    environment = default.create(

        feed=feed,
        portfolio=portfolio,
        action_scheme=action_scheme,
        reward_scheme="simple",
        renderer_feed=renderer_feed,
        renderer=PositionChangeChart(),
        window_size=config["window_size"],
        min_periods=20,
        max_allowed_loss=0.6
    )
    return environment
Exemple #21
0
    def create_env(config):

        # Use config param to decide which data set to use
        # Reserve 50 rows of data to fill in NaN values
        if config["train"] == True:
            df = data[50:-dataEnd]
            envData = candles[50:-dataEnd]
            taData = data[:-dataEnd]
        else:
            df = data[-dataEnd:]
            envData = candles[-dataEnd:]
            taData = data[-dataEnd - 50:]

        # === OBSERVER ===
        p = Stream.source(df[(coin + ':close')].tolist(),
                          dtype="float").rename(("USD-" + coin))

        # === EXCHANGE ===
        # Commission on Binance is 0.075% on the lowest level, using BNB (https://www.binance.com/en/fee/schedule)
        binance_options = ExchangeOptions(commission=0.0075,
                                          min_trade_price=10.0)
        binance = Exchange("binance",
                           service=execute_order,
                           options=binance_options)(p)

        # === ORDER MANAGEMENT SYSTEM ===
        # Start with 100.000 usd and 0 assets
        cash = Wallet(binance, 100000 * USD)
        asset = Wallet(binance, 0 * coinInstrument)

        portfolio = Portfolio(USD, [cash, asset])

        # === OBSERVER ===
        dataset = pd.DataFrame()

        # Use log-returns instead of raw OHLCV. This is a refined version of naive standarization
        # log(current_price / previous_price) = log(current_price) - log(previous_price)
        # If log value below 0 current_price > previous_price
        # Above 0 means current_price < previous_price
        dataset['log_open'] = np.log(taData[(coin + ':open')]) - np.log(
            taData[(coin + ':open')].shift(1))
        dataset['log_low'] = np.log(taData[(coin + ':low')]) - np.log(
            taData[(coin + ':low')].shift(1))
        dataset['log_high'] = np.log(taData[(coin + ':high')]) - np.log(
            taData[(coin + ':high')].shift(1))
        dataset['log_close'] = np.log(taData[(coin + ':close')]) - np.log(
            taData[(coin + ':close')].shift(1))
        dataset['log_vol'] = np.log(taData[(coin + ':volume')]) - np.log(
            taData[(coin + ':volume')].shift(1))

        # === TECHNICAL ANALYSIS ===
        # Extra features not described in research, therefore not used.
        #BB_low = ta.volatility.BollingerBands(close = taData[(coin + ':close')], window = 20).bollinger_lband()
        #BB_mid = ta.volatility.BollingerBands(close = taData[(coin + ':close')], window = 20).bollinger_mavg()
        #BB_high = ta.volatility.BollingerBands(close = taData[(coin + ':close')], window = 20).bollinger_hband()

        # Difference between close price and bollinger band
        #dataset['BB_low'] =  np.log(BB_low) - np.log(taData[(coin + ':close')])
        #dataset['BB_mid'] =  np.log(BB_mid) - np.log(taData[(coin + ':close')])
        #dataset['BB_high'] =  np.log(BB_high) - np.log(taData[(coin + ':close')])

        # Take log-returns to standardize
        # Log-returns can not be used if value is 0 or smaller.
        # Use pct_change() instead
        # IDEA: Maybe use volume or close to standardize

        # This line is necessary otherwise read only errors shows up
        taData = taData.copy()

        # For some reasons there are erros when using pct_change() for these indicators
        adi = ta.volume.AccDistIndexIndicator(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')],
            volume=taData[(coin + ':volume')]).acc_dist_index()
        dataset['adi'] = adi.pct_change()

        fi = ta.volume.ForceIndexIndicator(
            close=taData[(coin + ':close')],
            volume=taData[(coin + ':volume')]).force_index()
        dataset['fi'] = fi.pct_change()

        macd_diff = ta.trend.MACD(close=taData[(coin + ':close')]).macd_diff()
        dataset['macd_diff'] = macd_diff.pct_change()

        dpo = ta.trend.DPOIndicator(close=taData[(coin + ':close')]).dpo()
        dataset['dpo'] = dpo.pct_change()

        # Too many outliers in the dataset
        #vpt = ta.volume.VolumePriceTrendIndicator(close=taData[(coin + ':close')], volume=taData[(coin + ':volume')]).volume_price_trend()
        #dataset['vpt'] = vpt.pct_change()
        #em = ta.volume.EaseOfMovementIndicator(high=taData[(coin + ':high')], low=taData[(coin + ':low')], volume=taData[(coin + ':volume')]).ease_of_movement()
        #dataset['em'] = em.pct_change()

        kst_sig = ta.trend.KSTIndicator(close=taData[(coin +
                                                      ':close')]).kst_sig()
        dataset['kst_sig'] = kst_sig.pct_change()

        kst_diff = ta.trend.KSTIndicator(close=taData[(coin +
                                                       ':close')]).kst_diff()
        dataset['kst_diff'] = kst_diff.pct_change()

        nvi = ta.volume.NegativeVolumeIndexIndicator(
            close=taData[(coin + ':close')],
            volume=taData[(coin + ':volume')]).negative_volume_index()
        dataset['nvi'] = np.log(nvi) - np.log(nvi.shift(1))

        bbw = ta.volatility.BollingerBands(
            close=taData[(coin + ':close')]).bollinger_wband()
        dataset['bbw'] = np.log(bbw) - np.log(bbw.shift(1))

        kcw = ta.volatility.KeltnerChannel(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')]).keltner_channel_wband()
        dataset['kcw'] = np.log(kcw) - np.log(kcw.shift(1))

        dcw = ta.volatility.DonchianChannel(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')]).donchian_channel_wband()
        dataset['dcw'] = np.log(dcw) - np.log(dcw.shift(1))

        psar_up = ta.trend.PSARIndicator(high=taData[(coin + ':high')],
                                         low=taData[(coin + ':low')],
                                         close=taData[(coin +
                                                       ':close')]).psar_up()
        dataset['psar_up'] = np.log(psar_up) - np.log(psar_up.shift(1))

        # These indicators have a mean independent of the OHLCV data
        # IDEA: Use log-returns on these as an extra indicator
        # Has a mean of 0
        dataset['cmf'] = ta.volume.ChaikinMoneyFlowIndicator(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')],
            volume=taData[(coin + ':volume')]).chaikin_money_flow()
        dataset['ppo'] = ta.momentum.PercentagePriceOscillator(
            close=taData[(coin + ':close')]).ppo()
        dataset['ppo_signal'] = ta.momentum.PercentagePriceOscillator(
            close=taData[(coin + ':close')]).ppo_signal()
        dataset['ppo_hist'] = ta.momentum.PercentagePriceOscillator(
            close=taData[(coin + ':close')]).ppo_hist()
        dataset['ui'] = ta.volatility.UlcerIndex(
            close=taData[(coin + ':close')]).ulcer_index()
        dataset['aroon_ind'] = ta.trend.AroonIndicator(
            close=taData[(coin + ':close')]).aroon_indicator()

        # Indicator, so has value 0 or 1
        dataset['bbhi'] = ta.volatility.BollingerBands(
            close=taData[(coin + ':close')]).bollinger_hband_indicator()
        dataset['bbli'] = ta.volatility.BollingerBands(
            close=taData[(coin + ':close')]).bollinger_lband_indicator()
        dataset['kchi'] = ta.volatility.KeltnerChannel(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')]).keltner_channel_hband_indicator()
        dataset['kcli'] = ta.volatility.KeltnerChannel(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')]).keltner_channel_lband_indicator()

        # Has a mean of 50
        dataset['stoch_rsi'] = ta.momentum.StochRSIIndicator(
            close=taData[(coin + ':close')]).stochrsi()
        dataset['stoch_rsi_d'] = ta.momentum.StochRSIIndicator(
            close=taData[(coin + ':close')]).stochrsi_d()
        dataset['stoch_rsi_k'] = ta.momentum.StochRSIIndicator(
            close=taData[(coin + ':close')]).stochrsi_k()
        dataset['uo'] = ta.momentum.UltimateOscillator(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')],
            close=taData[(coin + ':close')]).ultimate_oscillator()
        dataset['adx'] = ta.trend.ADXIndicator(high=taData[(coin + ':high')],
                                               low=taData[(coin + ':low')],
                                               close=taData[(coin +
                                                             ':close')]).adx()
        dataset['mass_index'] = ta.trend.MassIndex(
            high=taData[(coin + ':high')],
            low=taData[(coin + ':low')]).mass_index()
        dataset['aroon_up'] = ta.trend.AroonIndicator(
            close=taData[(coin + ':close')]).aroon_up()
        dataset['aroon_down'] = ta.trend.AroonIndicator(
            close=taData[(coin + ':close')]).aroon_down()
        dataset['stc'] = ta.trend.STCIndicator(close=taData[(coin +
                                                             ':close')]).stc()

        # Lot of NaN values
        #ta.trend.PSARIndicator(high=df[(coin + ':high')], low=df[(coin + ':low')], close=df[(coin + ':close')]).psar_down()

        dataset = dataset.add_prefix(coin + ":")

        # Drop first 50 rows from dataset
        dataset = dataset.iloc[50:]

        with NameSpace("binance"):
            streams = [
                Stream.source(dataset[c].tolist(), dtype="float").rename(c)
                for c in dataset.columns
            ]

        # This is everything the agent gets to see, when making decisions
        feed = DataFeed(streams)

        # Compiles all the given stream together
        feed.compile()

        # Print feed for debugging
        #print(feed.next())
        #print(feed.next())
        #print(feed.next())

        # === REWARDSCHEME ===
        # RiskAdjustedReturns rewards depends on return_algorithm and its parameters.
        # The risk-free rate is the return that you can expect from taking on zero risk.
        # A target return is what an investor would want to make from any capital invested in the asset.

        # SimpleProfit() or RiskAdjustedReturns() or PBR()
        #reward_scheme = RiskAdjustedReturns(return_algorithm='sortino')#, risk_free_rate=0, target_returns=0)
        #reward_scheme = RiskAdjustedReturns(return_algorithm='sharpe', risk_free_rate=0, target_returns=0, window_size=config["window_size"])

        reward_scheme = SimpleProfit(window_size=config["window_size"])
        #reward_scheme = PBR(price=p)

        # === ACTIONSCHEME ===
        # SimpleOrders() or ManagedRiskOrders() or BSH()

        # ManagedRiskOrders is bad, with default settings!
        # To use ManagedRiskOrders use settings like these:
        # ManagedRiskOrders(stop = [0.02], take = [0.03], trade_sizes=2,)

        action_scheme = ManagedRiskOrders(durations=[100])

        #action_scheme = SimpleOrders()

        #BSH only works with PBR as reward_scheme
        #action_scheme = BSH(cash=cash,asset=asset).attach(reward_scheme)

        # === RENDERER ===
        # Uses the OHCLV data passed to envData
        renderer_feed = DataFeed([
            Stream.source(envData[c].tolist(), dtype="float").rename(c)
            for c in envData
        ])

        # === RESULT ===
        environment = default.create(
            feed=feed,
            portfolio=portfolio,
            action_scheme=action_scheme,
            reward_scheme=reward_scheme,
            renderer_feed=renderer_feed,
            renderer=PlotlyTradingChart(),  #PositionChangeChart()
            window_size=config["window_size"],  #part of OBSERVER
            max_allowed_loss=config["max_allowed_loss"]  #STOPPER
        )
        return environment
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
Exemple #23
0
def test_is_executable_on(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

    # Market order
    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=5000.00 * USD,
                  portfolio=portfolio,
                  price=Decimal(7000.00))

    exchange.quote_price = mock.Mock(return_value=Decimal(6800.00))
    assert order.is_executable

    exchange.quote_price = mock.Mock(return_value=Decimal(7200.00))
    assert order.is_executable

    # Limit order
    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.LIMIT,
                  quantity=5000.00 * USD,
                  portfolio=portfolio,
                  price=Decimal(7000.00))

    exchange.quote_price = mock.Mock(return_value=Decimal(6800.00))
    assert order.is_executable

    exchange.quote_price = mock.Mock(return_value=Decimal(7200.00))
    assert order.is_executable

    # Stop Order
    wallets = [Wallet(exchange, 0 * USD), Wallet(exchange, 2 * BTC)]
    portfolio = Portfolio(USD, wallets)
    order = Order(step=0,
                  exchange_pair=ExchangePair(exchange, USD / BTC),
                  side=TradeSide.SELL,
                  trade_type=TradeType.LIMIT,
                  quantity=1 * BTC,
                  portfolio=portfolio,
                  price=Decimal(7000.00),
                  criteria=Stop("down", 0.03))

    exchange.quote_price = mock.Mock(return_value=Decimal(1 - 0.031) *
                                     order.price)
    assert order.is_executable

    exchange.quote_price = mock.Mock(return_value=Decimal(1 - 0.02) *
                                     order.price)
    assert not order.is_executable
Exemple #24
0
def build_env(config):
    worker_index = 1
    if hasattr(config, 'worker_index'):
        worker_index = config.worker_index

    raw_data = pd.read_csv(btc_usd_file, sep=';')
    raw_data['date'] = pd.to_datetime(raw_data['time'], unit='ms')
    data = compute_features(raw_data)

    features = []
    for c in data.columns:
        if c not in raw_data.columns:
            s = Stream.source(list(data[c]),
                              dtype="float").rename(data[c].name)
            features += [s]

    comm = 0.00001
    coinbase = Exchange("coinbase",
                        service=execute_order,
                        options=ExchangeOptions(commission=comm))(
                            Stream.source(list(data["close"]),
                                          dtype="float").rename("USD-BTC"))

    cash = Wallet(coinbase, 10000 * USD)
    asset = Wallet(coinbase, 0 * BTC)

    portfolio = Portfolio(USD, [cash, asset])

    renderer_feed = DataFeed([
        Stream.source(list(data["date"])).rename("date"),
        Stream.source(list(data["open"]), dtype="float").rename("open"),
        Stream.source(list(data["high"]), dtype="float").rename("high"),
        Stream.source(list(data["low"]), dtype="float").rename("low"),
        Stream.source(list(data["close"]), dtype="float").rename("close"),
        Stream.source(list(data["volume"]), dtype="float").rename("volume")
    ])

    # reward_scheme = rewards.SimpleProfit()
    rsi = Stream.select(features, lambda x: x.name == "rsi")
    reward_scheme = SparseReward(rsi=rsi, window_size=10)
    action_scheme = BuySellHoldActionSchemes(cash, asset)
    action_scheme.attach(reward_scheme)

    plotly = PlotlyTradingChart(display=True, height=700, save_format="html")

    class EpisodeStopper(Stopper):
        def stop(self, env: 'TradingEnv') -> bool:
            return env.clock.num_steps > 1000

    open_position = Stream.sensor(asset,
                                  lambda a: asset.total_balance.as_float() > 0)
    # open_position = Stream.sensor(
    #     action_scheme, lambda action_scheme: action_scheme.has_asset
    # )
    features.append(open_position)
    feed = DataFeed(features)
    feed.compile()

    env = default.create(
        portfolio=portfolio,
        action_scheme=action_scheme,
        reward_scheme=reward_scheme,
        feed=feed,
        renderer_feed=renderer_feed,
        renderer=plotly,
        window_size=20,
        max_allowed_loss=0.5,
        stopper=EpisodeStopper(),
        callback=(LoggingCallback('http://165.227.193.153:8050', plotly)
                  if worker_index == 1 else None))

    import logging
    import os
    LOGGER = logging.getLogger(__name__)
    logging.basicConfig(
        level=logging.INFO,
        format=
        '%(asctime)s - %(name)s [%(threadName)s] - %(levelname)s - %(message)s',
    )
    LOGGER.info('env created logger')
    LOGGER.info(f'env: {os.environ}')
    print(f'env: {os.environ}')
    print('env created')

    return env
Exemple #25
0
def create_env(config, save_path='./agents/charts/', is_eval=False):

    # Load data
    k = -3000
    w = -200
    if is_eval:
        k = -200
        w = None
    y = data['Close'][k:w].to_numpy()

    features = []
    for c in data.columns[5:]:
        s = Stream.source(list(data[c][k:w]),
                          dtype="float").rename(data[c].name)
        features += [s]

    cp = Stream.source(y, dtype="float").rename("EUR-USD")

    coinbase = Exchange("coinbase",
                        service=execute_order,
                        options=ExchangeOptions(commission=0.00005))(cp)

    feature_add = [
        cp,
        cp.ewm(span=10).mean().rename("fast"),
        cp.ewm(span=50).mean().rename("medium"),
        cp.ewm(span=100).mean().rename("slow"),
        cp.log().diff().fillna(0).rename("lr")
    ]
    features = features + feature_add

    feed = DataFeed(features)

    feed.compile()

    cash = Wallet(coinbase, 10000 * EUR)
    asset = Wallet(coinbase, 10000 * USD)

    portfolio = Portfolio(EUR, [cash, asset])

    reward_scheme = PBR(price=cp)
    # reward_scheme = SimpleProfit(window_size=500)

    action_scheme = BSH(cash=cash, asset=asset).attach(reward_scheme)

    # renderer_feed = DataFeed([
    #     Stream.source(y, dtype="float").rename("price"),
    #     Stream.sensor(action_scheme, lambda s: s.action, dtype="float").rename("action")
    # ])

    renderer_feed = DataFeed([
        Stream.source(list(data["Date"][k:w])).rename("date"),
        Stream.source(list(data["Open"][k:w]), dtype="float").rename("open"),
        Stream.source(list(data["High"][k:w]), dtype="float").rename("high"),
        Stream.source(list(data["Low"][k:w]), dtype="float").rename("low"),
        Stream.source(list(data["Close"][k:w]), dtype="float").rename("close"),
        Stream.source(list(data["Volume"][k:w]),
                      dtype="float").rename("volume")
    ])

    environment = default.create(
        feed=feed,
        portfolio=portfolio,
        action_scheme=action_scheme,  #"managed-risk",
        reward_scheme=reward_scheme,
        renderer_feed=renderer_feed,
        renderer=default.renderers.PlotlyTradingChart(display=False,
                                                      save_format='html',
                                                      path=save_path),
        # renderer=PositionChangeChart(),
        window_size=config["window_size"],
        max_allowed_loss=0.6)
    return environment
Exemple #26
0
        'Low':'low',
        'High':'high',
        'Volume':'volume'
    }, inplace = True)

    df_USD = df_USD[df_USD['close'].notnull()]
    dataset = ta.add_all_ta_features(df_USD, 'open', 'high', 'low', 'close', 'volume', fillna=True)

    price_history = dataset[['date', 'open', 'high', 'low', 'close', 'volume']]  # chart data
    dataset.drop(columns=['date', 'open', 'high', 'low', 'close', 'volume'], inplace=True)

    micex = Exchange("MICEX", 
                    service=execute_order, 
                    options=ExchangeOptions(commission = 0.0003, #0.003,
                                            min_trade_size = 1e-6,
                                            max_trade_size = 1e6,
                                            min_trade_price = 1e-8,
                                            max_trade_price= 1e8,
                                            is_live=False)  )(
                                                Stream.source(price_history['close'].tolist(), dtype="float").rename("RUR-USD"))

    portfolio = Portfolio(RUR, [
        Wallet(micex, 0 * USD),
        Wallet(micex, 73000 * RUR),
    ])

    with NameSpace("MICEX"):
        streams = [Stream.source(dataset[c].tolist(), dtype="float").rename(c) for c in dataset.columns]

    feed = DataFeed(streams)
    feed.next()