def __init__(self,
                 q,
                 api_key='',
                 api_secret='',
                 instrument='',
                 method: StreamingMethod = StreamingMethod.AccountUpdate,
                 base_url='',
                 data_url='',
                 data_feed='iex',
                 *args,
                 **kwargs):
        try:
            # make sure we have an event loop, if not create a new one
            asyncio.get_event_loop()
        except RuntimeError:
            asyncio.set_event_loop(asyncio.new_event_loop())

        self.conn = Stream(api_key,
                           api_secret,
                           base_url,
                           data_stream_url=data_url,
                           data_feed=data_feed)
        self.instrument = instrument
        self.method = method
        self.q = q
class AlpacaStream(StreamingAPI):
    def __init__(self, queues: QueueMapper):
        self.alpaca_ws_client = Stream(
            key_id=config.alpaca_api_key, secret_key=config.alpaca_api_secret
        )

        if not self.alpaca_ws_client:
            raise AssertionError(
                "Failed to authenticate Alpaca web_socket client"
            )
        self.alpaca_ws_client.subscribe_trade_updates(
            AlpacaStream.trade_update_handler
        )
        self.alpaca_ws_client.run()

        super().__init__(queues)

    @classmethod
    async def trade_update_handler(cls, msg):
        print(f"trade_update_handler:{msg}")

    @classmethod
    async def bar_handler(cls, msg):
        print(f"bar_handler:{msg}")

    @classmethod
    async def trades_handler(cls, msg):
        print(f"trades_handler:{msg}")

    @classmethod
    async def quotes_handler(cls, msg):
        print(f"quotes_handler:{msg}")

    async def subscribe(
        self, symbols: List[str], events: List[WSEventType]
    ) -> bool:
        for event in events:
            if event == WSEventType.SEC_AGG:
                raise NotImplementedError(
                    f"event {event} not implemente in Alpaca"
                )
            elif event == WSEventType.MIN_AGG:
                self.alpaca_ws_client.subscribe_bars(
                    AlpacaStream.bar_handler, symbols
                )
            elif event == WSEventType.TRADE:
                self.alpaca_ws_client.subscribe_trades(
                    AlpacaStream.trades_handler, symbols
                )
            elif event == WSEventType.QUOTE:
                self.alpaca_ws_client.subscribe_quotes(
                    AlpacaStream.quotes_handler, symbols
                )
        return True
Beispiel #3
0
def main():
    logging.basicConfig(level=logging.INFO)
    feed = 'iex'  # <- replace to SIP if you have PRO subscription
    stream = Stream(data_feed=feed, raw_data=True)
    stream.subscribe_trade_updates(print_trade_update)
    stream.subscribe_trades(print_trade, 'AAPL')
    stream.subscribe_quotes(print_quote, 'IBM')

    @stream.on_bar('MSFT')
    async def _(bar):
        print('bar', bar)

    stream.run()
Beispiel #4
0
    def __init__(self, qm: QueueMapper = None):
        self.market_open: Optional[datetime]
        self.market_close: Optional[datetime]

        self.alpaca_rest_client = REST(
            base_url=URL(config.alpaca_base_url),
            key_id=config.alpaca_api_key,
            secret_key=config.alpaca_api_secret,
        )
        if not self.alpaca_rest_client:
            raise AssertionError(
                "Failed to authenticate Alpaca RESTful client"
            )

        if qm:
            self.alpaca_ws_client = Stream(
                base_url=URL(config.alpaca_base_url),
                key_id=config.alpaca_api_key,
                secret_key=config.alpaca_api_secret,
            )
            if not self.alpaca_ws_client:
                raise AssertionError(
                    "Failed to authenticate Alpaca web_socket client"
                )
            self.alpaca_ws_client.subscribe_trade_updates(
                AlpacaTrader.trade_update_handler
            )
        self.running_task: Optional[asyncio.Task] = None

        now = datetime.now(nyc)
        calendar = self.alpaca_rest_client.get_calendar(
            start=now.strftime("%Y-%m-%d"), end=now.strftime("%Y-%m-%d")
        )[0]

        if now.date() >= calendar.date.date():
            self.market_open = now.replace(
                hour=calendar.open.hour,
                minute=calendar.open.minute,
                second=0,
                microsecond=0,
            )
            self.market_close = now.replace(
                hour=calendar.close.hour,
                minute=calendar.close.minute,
                second=0,
                microsecond=0,
            )
        else:
            self.market_open = self.market_close = None
        super().__init__(qm)
Beispiel #5
0
    def __init__(self, queues: QueueMapper):
        self.alpaca_ws_client = Stream(
            base_url=URL(config.alpaca_base_url),
            key_id=config.alpaca_api_key,
            secret_key=config.alpaca_api_secret,
            data_feed="sip",  # config.alpaca_data_feed,
        )

        if not self.alpaca_ws_client:
            raise AssertionError(
                "Failed to authenticate Alpaca web_socket client")

        self.running = False
        super().__init__(queues)
    def __init__(self, queues: QueueMapper):
        self.alpaca_ws_client = Stream(
            key_id=config.alpaca_api_key, secret_key=config.alpaca_api_secret
        )

        if not self.alpaca_ws_client:
            raise AssertionError(
                "Failed to authenticate Alpaca web_socket client"
            )
        self.alpaca_ws_client.subscribe_trade_updates(
            AlpacaStream.trade_update_handler
        )
        self.alpaca_ws_client.run()

        super().__init__(queues)
class Streamer:
    conn = None

    def __init__(self,
                 q,
                 api_key='',
                 api_secret='',
                 instrument='',
                 method: StreamingMethod = StreamingMethod.AccountUpdate,
                 base_url='',
                 data_url='',
                 data_feed='iex',
                 *args,
                 **kwargs):
        try:
            # make sure we have an event loop, if not create a new one
            asyncio.get_event_loop()
        except RuntimeError:
            asyncio.set_event_loop(asyncio.new_event_loop())

        self.conn = Stream(api_key,
                           api_secret,
                           base_url,
                           data_stream_url=data_url,
                           data_feed=data_feed)
        self.instrument = instrument
        self.method = method
        self.q = q

    def run(self):
        if self.method == StreamingMethod.AccountUpdate:
            self.conn.subscribe_trade_updates(self.on_trade)
        elif self.method == StreamingMethod.MinuteAgg:
            self.conn.subscribe_bars(self.on_agg_min, self.instrument)
        elif self.method == StreamingMethod.Quote:
            self.conn.subscribe_quotes(self.on_quotes, self.instrument)

        # this code runs in a new thread. we need to set the loop for it
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        self.conn.run()

    async def on_listen(self, conn, stream, msg):
        pass

    async def on_quotes(self, msg):
        msg._raw['time'] = msg.timestamp
        self.q.put(msg._raw)

    async def on_agg_min(self, msg):
        msg._raw['time'] = msg.timestamp
        self.q.put(msg._raw)

    async def on_account(self, msg):
        self.q.put(msg)

    async def on_trade(self, msg):
        self.q.put(msg)
Beispiel #8
0
    def __init__(self, tickers, alpaca_key, alpaca_secret_key, history_len, trend_len):
        # all for hashless O(1) access of our sweet sweet data
        self.tickers = tickers
        self.tickers_to_indices = {}
        for i in range(len(tickers)):
            self.tickers_to_indices[tickers[i]] = i
        self.stream = Stream(alpaca_key, alpaca_secret_key, data_feed='iex')

        initial_data = r.stocks.get_latest_price(self.tickers, priceType=None, includeExtendedHours=True)
        self.data = []
        for ticker in tickers:
            # for each ticker, we need:
            # - most recent price
            # - rwlock
            # - callback function for stream that updates most recent price
            ticker_data = TickerData(initial_data[self.tickers_to_indices[ticker]], history_len, trend_len)
            self.stream.subscribe_trades(ticker_data.trade_update_callback, ticker)
            self.data.append(ticker_data)
def consumer_thread():
    global conn
    conn = Stream(ALPACA_API_KEY,
                  ALPACA_SECRET_KEY,
                  base_url=URL('https://paper-api.alpaca.markets'),
                  data_feed='iex')

    conn.subscribe_quotes(print_quote, 'AAPL')
    conn.run()
Beispiel #10
0
def consumer_thread():
    try:
        # make sure we have an event loop, if not create a new one
        loop = asyncio.get_event_loop()
        loop.set_debug(True)
    except RuntimeError:
        asyncio.set_event_loop(asyncio.new_event_loop())

    global conn
    conn = Stream(ALPACA_API_KEY,
                  ALPACA_SECRET_KEY,
                  base_url=URL('https://paper-api.alpaca.markets'),
                  data_feed='iex')

    conn.subscribe_quotes(print_quote, 'AAPL')
    conn.run()
Beispiel #11
0
class MarketData:
    """Threadsafe class that handles the concurrent reading and writing of the market data
    for the relevant tickers. Should really be a singleton."""

    def __init__(self, tickers, alpaca_key, alpaca_secret_key, history_len, trend_len):
        # all for hashless O(1) access of our sweet sweet data
        self.tickers = tickers
        self.tickers_to_indices = {}
        for i in range(len(tickers)):
            self.tickers_to_indices[tickers[i]] = i
        self.stream = Stream(alpaca_key, alpaca_secret_key, data_feed='iex')

        initial_data = r.stocks.get_latest_price(self.tickers, priceType=None, includeExtendedHours=True)
        self.data = []
        for ticker in tickers:
            # for each ticker, we need:
            # - most recent price
            # - rwlock
            # - callback function for stream that updates most recent price
            ticker_data = TickerData(initial_data[self.tickers_to_indices[ticker]], history_len, trend_len)
            self.stream.subscribe_trades(ticker_data.trade_update_callback, ticker)
            self.data.append(ticker_data)

        # only start stream when the market is open
    
    def get_ticker_data_for_ticker(self, ticker):
        return self.data[self.tickers_to_indices[ticker]]

    def start_stream(self):
        """Call this function when the market is open.
        
        Starts a daemon thread which consumes new ticker updates
        from the Alpaca stream and updates the relevant data in this object."""
        self.stream_thread = threading.Thread(target=self.stream.run, daemon=True)
        self.stream_thread.start()

    def get_data_for_ticker(self, ticker):
        # can be called by any thread
        return self.get_ticker_data_for_ticker(ticker).get_price()

    def get_next_data_for_ticker(self, ticker):
        return self.get_ticker_data_for_ticker(ticker).get_next_price()

    def get_trend_for_ticker(self, ticker):
        return self.get_ticker_data_for_ticker(ticker).get_trend()
    
    def get_first_price_of_day_for_ticker(self, ticker):
        return self.get_ticker_data_for_ticker(ticker).get_first_price_of_day()

    def print_data(self):
        """Pretty printing for the internal data of this object."""
        print_with_lock("---- MARKET DATA ----")
        for ticker, index in self.tickers_to_indices.items():
            ticker_data = self.data[index]
            with ticker_data.lock.gen_rlock():
                if len(ticker_data.prices) < ticker_data.trend_len:
                    # make a reversed copy of the list
                    data_snippet = ticker_data.prices[::-1]
                else:
                    data_snippet = ticker_data.get_last_k_prices_in_order()
                
                # data will always be nonempty for a ticker
                print_with_lock("{}: {} {}".format(ticker, data_snippet[0], data_snippet))
        print_with_lock("---------------------")
Beispiel #12
0
class AlpacaTrader(Trader):
    def __init__(self, qm: QueueMapper = None):
        self.market_open: Optional[datetime]
        self.market_close: Optional[datetime]

        self.alpaca_rest_client = REST(
            base_url=URL(config.alpaca_base_url),
            key_id=config.alpaca_api_key,
            secret_key=config.alpaca_api_secret,
        )
        if not self.alpaca_rest_client:
            raise AssertionError(
                "Failed to authenticate Alpaca RESTful client"
            )

        if qm:
            self.alpaca_ws_client = Stream(
                base_url=URL(config.alpaca_base_url),
                key_id=config.alpaca_api_key,
                secret_key=config.alpaca_api_secret,
            )
            if not self.alpaca_ws_client:
                raise AssertionError(
                    "Failed to authenticate Alpaca web_socket client"
                )
            self.alpaca_ws_client.subscribe_trade_updates(
                AlpacaTrader.trade_update_handler
            )
        self.running_task: Optional[asyncio.Task] = None

        now = datetime.now(nyc)
        calendar = self.alpaca_rest_client.get_calendar(
            start=now.strftime("%Y-%m-%d"), end=now.strftime("%Y-%m-%d")
        )[0]

        if now.date() >= calendar.date.date():
            self.market_open = now.replace(
                hour=calendar.open.hour,
                minute=calendar.open.minute,
                second=0,
                microsecond=0,
            )
            self.market_close = now.replace(
                hour=calendar.close.hour,
                minute=calendar.close.minute,
                second=0,
                microsecond=0,
            )
        else:
            self.market_open = self.market_close = None
        super().__init__(qm)

    async def is_order_completed(self, order) -> Tuple[bool, float]:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        status = self.alpaca_rest_client.get_order(order_id=order.id)
        if status.filled_qty == order.qty:
            return True, float(status.filled_avg_price)

        return False, 0.0

    def get_market_schedule(
        self,
    ) -> Tuple[Optional[datetime], Optional[datetime]]:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        return self.market_open, self.market_close

    def get_trading_days(
        self, start_date: date, end_date: date = date.today()
    ) -> pd.DataFrame:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        calendars = self.alpaca_rest_client.get_calendar(
            start=str(start_date), end=str(end_date)
        )
        _df = pd.DataFrame.from_dict([calendar._raw for calendar in calendars])
        _df["date"] = pd.to_datetime(_df.date)
        return _df.set_index("date")

    def get_position(self, symbol: str) -> float:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")
        return self.alpaca_rest_client.get_position(symbol)

    async def get_order(self, order_id: str):
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")
        return self.alpaca_rest_client.get_order(order_id)

    def is_market_open_today(self) -> bool:
        return self.market_open is not None

    def get_time_market_close(self) -> Optional[timedelta]:
        if not self.is_market_open_today():
            raise AssertionError("Market closed today")

        return (
            self.market_close - datetime.now(nyc)
            if self.market_close
            else None
        )

    async def reconnect(self):
        self.alpaca_rest_client = REST(
            key_id=config.alpaca_api_key, secret_key=config.alpaca_api_secret
        )
        if not self.alpaca_rest_client:
            raise AssertionError(
                "Failed to authenticate Alpaca RESTful client"
            )

    async def run(self) -> Optional[asyncio.Task]:
        if not self.running_task:
            tlog("starting Alpaca listener")
            self.running_task = asyncio.create_task(
                self.alpaca_ws_client._trading_ws._run_forever()
            )
        return self.running_task

    async def close(self):
        if not self.alpaca_ws_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")
        if self.running_task:
            await self.alpaca_ws_client.stop_ws()

    async def get_tradeable_symbols(self) -> List[str]:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        data = self.alpaca_rest_client.list_assets()
        return [asset.symbol for asset in data if asset.tradable]

    async def get_shortable_symbols(self) -> List[str]:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        data = self.alpaca_rest_client.list_assets()
        return [
            asset.symbol
            for asset in data
            if asset.tradable and asset.easy_to_borrow and asset.shortable
        ]

    async def is_shortable(self, symbol) -> bool:
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        asset = self.alpaca_rest_client.get_asset(symbol)
        return (
            asset.tradable is not False
            and asset.shortable is not False
            and asset.status != "inactive"
            and asset.easy_to_borrow is not False
        )

    async def cancel_order(self, order_id: str):
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        self.alpaca_rest_client.cancel_order(order_id)

    async def submit_order(
        self,
        symbol: str,
        qty: float,
        side: str,
        order_type: str,
        time_in_force: str,
        limit_price: str = None,
        stop_price: str = None,
        client_order_id: str = None,
        extended_hours: bool = None,
        order_class: str = None,
        take_profit: dict = None,
        stop_loss: dict = None,
        trail_price: str = None,
        trail_percent: str = None,
    ):
        if not self.alpaca_rest_client:
            raise AssertionError("Must call w/ authenticated Alpaca client")

        return self.alpaca_rest_client.submit_order(
            symbol,
            str(qty),
            side,
            order_type,
            time_in_force,
            limit_price,
            stop_price,
            client_order_id,
            extended_hours,
            order_class,
            take_profit,
            stop_loss,
            trail_price,
            trail_percent,
        )

    @classmethod
    async def trade_update_handler(cls, data):
        symbol = data.__dict__["_raw"]["order"]["symbol"]
        data.__dict__["_raw"]["EV"] = "trade_update"
        data.__dict__["_raw"]["symbol"] = symbol
        try:
            cls.get_instance().queues[symbol].put(
                data.__dict__["_raw"], timeout=1
            )
        except queue.Full as f:
            tlog(
                f"[EXCEPTION] process_message(): queue for {symbol} is FULL:{f}, sleeping for 2 seconds and re-trying."
            )
            raise
        except AssertionError:
            for q in cls.get_instance().queues.get_allqueues():
                q.put(data.__dict__["_raw"], timeout=1)
        except Exception as e:
            tlog(f"[EXCEPTION] process_message(): exception {e}")
            traceback.print_exc()
Beispiel #13
0
import traceback

import Util

import alpaca_trade_api as tradeapi
from alpaca_trade_api.stream import Stream
from alpaca_trade_api.common import URL

ACCOUNT_STATUS_ACTIVE = "ACTIVE"
NANOSEC = 10**9

#core_domain = "https://api.alpaca.markets"
core_domain = "https://paper-api.alpaca.markets"
data_domain = "https://data.alpaca.markets"

conn = Stream(base_url=URL(core_domain), data_feed='iex')

async def on_minute_bars(bar):
    symbol = bar.symbol
    mins = 1

    # BIG TODO - TIME (mins) SHOULD NOT BE HARDCODED
    
    epsilon = 30
    bar_time = bar.timestamp / NANOSEC
    time_range_floor = (60 * mins - epsilon) + Core.prev_time[symbol]
    time_range_ceil  = (60 * mins + epsilon) + Core.prev_time[symbol]
    if time_range_floor < bar_time and bar_time < time_range_ceil:
        curr = bar.close
        change = curr - Core.prev_close[symbol]
        if change > 0:
Beispiel #14
0
def main():
    logging.basicConfig(level=logging.INFO)
    feed = 'iex'  # <- replace to SIP if you have PRO subscription
    stream = Stream(data_feed=feed, raw_data=True)
    stream.subscribe_trade_updates(print_trade_update)
    stream.subscribe_trades(print_trade, 'AAPL')
    stream.subscribe_quotes(print_quote, 'IBM')
    stream.subscribe_crypto_trades(print_crypto_trade, 'BTCUSD')

    @stream.on_bar('MSFT')
    async def _(bar):
        print('bar', bar)

    @stream.on_updated_bar('MSFT')
    async def _(bar):
        print('updated bar', bar)

    @stream.on_status("*")
    async def _(status):
        print('status', status)

    @stream.on_luld('AAPL', 'MSFT')
    async def _(luld):
        print('LULD', luld)

    stream.run()
Beispiel #15
0
class AlpacaStream(StreamingAPI):
    def __init__(self, queues: QueueMapper):
        self.alpaca_ws_client = Stream(
            base_url=URL(config.alpaca_base_url),
            key_id=config.alpaca_api_key,
            secret_key=config.alpaca_api_secret,
            data_feed="sip",  # config.alpaca_data_feed,
        )

        if not self.alpaca_ws_client:
            raise AssertionError(
                "Failed to authenticate Alpaca web_socket client")

        self.running = False
        super().__init__(queues)

    async def run(self):
        if not self.running:
            if not self.queues:
                raise AssertionError(
                    "can't call `AlpacaStream.run()` without queues")

            asyncio.create_task(self.alpaca_ws_client._run_forever())
            self.running = True

    @classmethod
    async def bar_handler(cls, msg):
        try:
            event = {
                "symbol": msg.symbol,
                "open": msg.open,
                "close": msg.close,
                "high": msg.high,
                "low": msg.low,
                "start": int(msg.timestamp // 1000000),
                "volume": msg.volume,
                "count": 0.0,
                "vwap": 0.0,
                "average": 0.0,
                "totalvolume": None,
                "EV": "AM",
            }
            cls.get_instance().queues[msg.symbol].put(event, timeout=1)
        except queue.Full as f:
            tlog(
                f"[EXCEPTION] process_message(): queue for {event['sym']} is FULL:{f}, sleeping for 2 seconds and re-trying."
            )
            raise
        except Exception as e:
            tlog(
                f"[EXCEPTION] process_message(): exception of type {type(e).__name__} with args {e.args}"
            )
            traceback.print_exc()

    @classmethod
    async def trades_handler(cls, msg):
        try:
            event = {
                "symbol": msg.symbol,
                "price": msg.price,
                "timestamp": pd.to_datetime(msg.timestamp),
                "volume": msg.size,
                "exchange": msg.exchange,
                "conditions": msg.conditions,
                "tape": msg.tape,
                "EV": "T",
            }
            cls.get_instance().queues[msg.symbol].put(event, timeout=1)
        except queue.Full as f:
            tlog(
                f"[EXCEPTION] process_message(): queue for {event['sym']} is FULL:{f}, sleeping for 2 seconds and re-trying."
            )
            raise
        except Exception as e:
            tlog(
                f"[EXCEPTION] process_message(): exception of type {type(e).__name__} with args {e.args}"
            )
            traceback.print_exc()

    @classmethod
    async def quotes_handler(cls, msg):
        print(f"quotes_handler:{msg}")

    async def subscribe(self, symbols: List[str],
                        events: List[WSEventType]) -> bool:
        for event in events:
            if event == WSEventType.SEC_AGG:
                tlog(f"event {event} not implemented in Alpaca")
            elif event == WSEventType.MIN_AGG:
                self.alpaca_ws_client._data_ws._running = False
                self.alpaca_ws_client.subscribe_bars(AlpacaStream.bar_handler,
                                                     *symbols)
            elif event == WSEventType.TRADE:
                self.alpaca_ws_client.subscribe_trades(
                    AlpacaStream.trades_handler, *symbols)
            elif event == WSEventType.QUOTE:
                self.alpaca_ws_client.subscribe_quotes(
                    AlpacaStream.quotes_handler, *symbols)
        return True
Beispiel #16
0
    def start_trading(self):
        conn = Stream(
            self.key_id,
            self.secret_key,
            base_url=self.base_url,
            data_feed='iex')  # <- replace to SIP if you have PRO subscription

        # Listen for second aggregates and perform trading logic
        async def handle_bar(bar):
            self.tick_index = (self.tick_index + 1) % self.tick_size
            if self.tick_index == 0:
                # It's time to update

                # Update price info
                tick_open = self.last_price
                tick_close = bar.close
                self.last_price = tick_close

                self.process_current_tick(tick_open, tick_close)

        conn.subscribe_bars(handle_bar, self.symbol)

        # Listen for quote data and perform trading logic
        async def handle_trades(trade):
            now = datetime.datetime.utcnow()
            if now - self.last_trade_time < datetime.timedelta(seconds=1):
                # don't react every tick unless at least 1 second past
                return
            self.last_trade_time = now
            self.tick_index = (self.tick_index + 1) % self.tick_size
            if self.tick_index == 0:
                # It's time to update

                # Update price info
                tick_open = self.last_price
                tick_close = trade.price
                self.last_price = tick_close

                self.process_current_tick(tick_open, tick_close)

        conn.subscribe_trades(handle_trades, self.symbol)

        # Listen for updates to our orders
        async def handle_trade_updates(data):
            symbol = data.order['symbol']
            if symbol != self.symbol:
                # The order was for a position unrelated to this script
                return

            event_type = data.event
            qty = int(data.order['filled_qty'])
            side = data.order['side']
            oid = data.order['id']

            if event_type == 'fill' or event_type == 'partial_fill':
                # Our position size has changed
                self.position = int(data.position_qty)
                print(f'New position size due to order fill: {self.position}')
                if (event_type == 'fill' and self.current_order
                    and self.current_order.id == oid):
                    self.current_order = None
            elif event_type == 'rejected' or event_type == 'canceled':
                if self.current_order and self.current_order.id == oid:
                    # Our last order should be removed
                    self.current_order = None
            elif event_type != 'new':
                print(f'Unexpected order event type {event_type} received')

        conn.subscribe_trade_updates(handle_trade_updates)

        conn.run()