Esempio n. 1
0
class Trader(ABC):
    # TODO: For now we will run in a single thread with one instance of each trader 
    # however we will soon want to scale this up to many asyncio trader clones per core Process

    def __init__(self, enable_app=False, name='not_implemented'):
        ABC.__init__(self)
        self._connection_established = asyncio.Event()
        self._exchange_connection = ExchangeConnection(enable_app=enable_app, name=name, setup_event = self._connection_established)
        self._securities = {}

    async def connect(self): 
        """
        Must be called to start the bot!
        """
        await asyncio.gather(self._exchange_connection.connect_to_server(), self.on_connection())

    async def on_connection(self):
        await self._connection_established.wait()

        self.init_secuirties()

        await self.run()

    def init_secuirties(self):
        # Since the exchange connection is unique to the trader...
        self._securities = self._exchange_connection._security_objects

    @abstractmethod
    async def run(self):
        pass
Esempio n. 2
0
    def __init__(self, enable_app=False, name='not_implemented', exchange_names = ['BITSTAMP', 'LUNO']):
        ABC.__init__(self)
        
        self._connection_established = {name: asyncio.Event() for name in exchange_names}
        self._exchange_connections = {}
        self._securities = {}

        for idx, exchange_name in enumerate(exchange_names):
            conn = ExchangeConnection(enable_app=False, name=exchange_name, uri=self.get_ws_uri(exchange_name.lower()), setup_event = self._connection_established[idx])
            self._exchange_connections[exchange_name] = conn       
Esempio n. 3
0
    async def configure_exchanges(self):
        with open('./configs/backend_config.json') as config_file:
            config = json.load(config_file)

            # self.GLOBITEX =  ExchangeConnection(enable_app=False, name='GLOBITEX', uri=self.get_ws_uri(config, 'globitex'))
            # self.KRAKEN =  ExchangeConnection(enable_app=False, name='KRAKEN', uri=self.get_ws_uri(config, 'kraken'))
            # self.BITSTAMP =  ExchangeConnection(enable_app=False, name='BITSTAMP', uri=self.get_ws_uri(config, 'bitstamp'))
            self.LUNO =  ExchangeConnection(enable_app=False, name='LUNO', uri=self.get_ws_uri(config, 'luno'))
            # self.EXCHANGES = [self.BITSTAMP, self.LUNO]
            self.EXCHANGES = [self.LUNO]

            await asyncio.gather(*[bot.connect_to_server() for bot in self.EXCHANGES])
Esempio n. 4
0
    def __init__(self):  #From front end
        self.trader = ExchangeConnection(enable_app=True, name='TRADER')
        bot_1 = ExchangeConnection(enable_app=False, name='BOT1')
        bot_2 = ExchangeConnection(enable_app=False, name='BOT2')
        bot_3 = ExchangeConnection(enable_app=False, name='BOT3')
        self.mopup_bot = ExchangeConnection(enable_app=False, name='MOPUP')
        self.bots = [bot_1, bot_2, bot_3]

        loop = asyncio.get_event_loop()
        # loop.run_until_complete(asyncio.gather(self.run_script()))
        loop.run_until_complete(asyncio.gather(self.run_script()))
Esempio n. 5
0
class UnitTest():

    # -------- Helpers ----------
    def __init__(self):  #From front end
        self.trader = ExchangeConnection(enable_app=True, name='TRADER')
        bot_1 = ExchangeConnection(enable_app=False, name='BOT1')
        bot_2 = ExchangeConnection(enable_app=False, name='BOT2')
        bot_3 = ExchangeConnection(enable_app=False, name='BOT3')
        self.mopup_bot = ExchangeConnection(enable_app=False, name='MOPUP')
        self.bots = [bot_1, bot_2, bot_3]

        loop = asyncio.get_event_loop()
        # loop.run_until_complete(asyncio.gather(self.run_script()))
        loop.run_until_complete(asyncio.gather(self.run_script()))

    @staticmethod
    async def assert_order_execution(*orders):
        # Market vs Market
        to_execute = [order.execute() for order in orders]
        assert (all(await asyncio.gather(*to_execute)))

    # -------- Tests ----------

    async def validate_pricing_functions(self):
        edge = 1
        direction = 1
        price_fn = improve_on_best_quote(edge)
        price_improved = price_fn(direction, self.RITC.evaluate)

        assert (price_improved == self.RITC.evaluate(direction) - 1)
        print("[TEST] Imporve on best quote: Success!")

    async def validate_graph_pricing(self):
        UNDERLYINGS = self.BEAR + self.BULL
        SPREAD = self.RITC - self.USD * UNDERLYINGS

        for i in [-1, 0, 1]:
            spread_price = SPREAD.evaluate(i)
            resolution = Security.resolution(spread_price)
            i_inv = -1 * i

            ritc_price = self.RITC.evaluate(i)
            self.BEAR.evaluate(i_inv)
            self.BULL.evaluate(i_inv)
            self.USD.evaluate(i)

            underlying_price = self.BEAR.evaluate(i_inv) + self.BULL.evaluate(
                i_inv)
            true_spread_price = round(
                ritc_price - self.USD.evaluate(0) * underlying_price,
                resolution)

            assert (true_spread_price == spread_price)

        print("[TEST] Validate Graph Pricing : Success!")

    async def validate_mkt_order_execution(self):
        print("[TEST SUITE] Starting market order execution tests...")
        UNDERLYINGS = self.BEAR + self.BULL
        SPREAD = self.RITC - self.USD * UNDERLYINGS
        # SPREAD_USD_EXPSOURE = RITC * USD
        # HEDGED_SPREAD = SPREAD - SPREAD_USD_EXPSOURE

        ORDER = SPREAD.to_order(qty=100, order_type='MKT', group_name='MKT')
        SIGNED_ORDER = ORDER.inv_sign() * ORDER
        SIGNED_ORDER.group_name = 'SIGNED'

        await self.assert_order_execution(ORDER, SIGNED_ORDER)
        print("[TEST] Market - Market Order Transaction: Success!")

        # Simple Limit vs Market
        LMT_ORDER = self.RITC.to_order(qty=100,
                                       order_type='LMT',
                                       price_fn=improve_on_best_quote(1))
        MKT_ORDER = self.RITC.to_order(qty=100, order_type='MKT')
        SIGNED_MKT_ORDER = LMT_ORDER.inv_sign() * MKT_ORDER

        await self.assert_order_execution(LMT_ORDER, SIGNED_MKT_ORDER)
        print("[TEST] Limit - Market Order Transaction: Success!")

        # Complex vs Market
        # Note: A complex order is not added to the limit order book
        # Instead it is a Market Order with dispatch to server postponed until the limit price is within
        # some threshold of the best quote.

        # It is first of all clear that for both Complex MKT and Complex LMT orders they should not be executed
        # until there is SUFFICIENT LIQUIDITY for all orders to be executed (TODO)

        # The issue with Complex LMT Orders is that we can't place limit orders for multiple underlying products
        # As we have more unkowns than equations (1 aggregate price target). Thus we will create a new order
        # type called CMPLX to stress the point that it is a market order executable subject to a condition
        # rather than a limit order

        # TODO: Fix the contrived scenario to make it trigger the complex order. NOTE ADD Back in LMT_IMPROVE to execution
        # Contrived Orders to make the nex part of the test work
        # Imporve the best ask by 1
        # TODO: Fix this!
        LMT_IMPROVE = -1 * self.RITC.to_order(
            qty=10,
            order_type='LMT',
            price_fn=improve_on_best_quote(-1),
            group_name='LMT_IMPROVE')
        # Buy the spread at 1 below the market price -> Which we've setup to happen in the previous line!
        CMPLX_ORDER = SPREAD.to_order(
            qty=100,
            order_type='CMPLX',
            price_fn=improve_on_best_quote(1),
            group_name='CMPLX_ORDER'
        )  # Place a buy limit order at current market best bid

        # CMPLX_ORDER = SPREAD.to_order(qty=100, order_type='CMPLX', price_fn=improve_on_best_quote(0)) # Place a buy limit order at current market best bid
        MKT_ORDER = SPREAD.to_order(qty=100,
                                    order_type='MKT',
                                    group_name='MKT_ORDER')
        SIGNED_MKT_ORDER = SPREAD.inv_sign() * MKT_ORDER

        # Mops up the LMT_Imporve which did not improve enough to cross
        # the spread and thus was not executed as a marketable limit order
        LMT_IMPROVE_MOPUP = self.RITC.to_order(qty=10,
                                               order_type='MKT',
                                               group_name='LMT_IMPROVE_MOPUP')

        await asyncio.gather(
            LMT_IMPROVE_MOPUP.execute_later(delay=1),
            self.assert_order_execution(CMPLX_ORDER, LMT_IMPROVE,
                                        SIGNED_MKT_ORDER))

        print("[TEST] Complex Limit - Market Order Transaction: Success!")

        # Marketable Limit vs Limit
        LMT_IMPROVE = self.RITC.to_order(qty=10,
                                         order_type='LMT',
                                         price_fn=improve_on_best_quote(-3),
                                         group_name='LMT_IMPROVE')

        LMT = -1 * self.RITC.to_order(qty=10,
                                      order_type='LMT',
                                      price_fn=improve_on_best_quote(0),
                                      group_name='LMT')

        await self.assert_order_execution(LMT_IMPROVE, LMT)
        print("[TEST] Marketable Limit - Limit Order Transaction: Success!")

        # Marketable Limit vs Market

        LMT_IMPROVE = self.RITC.to_order(qty=10,
                                         order_type='LMT',
                                         price_fn=improve_on_best_quote(-3),
                                         group_name='LMT_IMPROVE')

        MKT = -1 * self.RITC.to_order(
            qty=10, order_type='MKT', group_name='MKT')

        await self.assert_order_execution(LMT_IMPROVE, MKT)
        print("[TEST] Marketable Limit - Limit Order Transaction: Success!")

        # Sequence Orders
        LMT = self.RITC.to_order(qty=10,
                                 order_type='LMT',
                                 price_fn=improve_on_best_quote(0),
                                 group_name='LMT')
        MKT = -1 * self.RITC.to_order(
            qty=20, order_type='MKT', group_name='MKT')
        MOPUP_LMT = self.RITC.to_order(qty=10,
                                       order_type='LMT',
                                       price_fn=improve_on_best_quote(0),
                                       group_name='MOPUP_LMT')
        SEQ = LMT.then(MOPUP_LMT)

        await self.assert_order_execution(SEQ, MKT)
        print("[TEST] Sequence Order Transaction: Success!")
        print("[TEST SUITE] Finished market order execution tests...")

        #
        # In order to do this we need to establish the frontend connection to the web app
        # TODO: Code up some bots (But again would be nice to have the trader private view first...)
        # Which will involve creating a private trader view

        # TODO: Test conditional orders
        # TODO: In order to test the this properly we need to be able to register and display
        # # synthetic product price charts to properly debug.
        # NOTE: Think about converting mkt orders to limit orders
        # in very illiquid markets cause thr prices are probably
        # really poor
        # TODO: Decide where to encorporate RISK MANAGEMENT into the frontend
        # maybe in the base_canc_execute blocks, but will need some explicit
        # lookahead management to see if the entire transaction sequence
        # is feasible accross the entire algorithm :) Now that would be cool!
        # This is really important especially for tenders
        # TODO: Implement risk limits

        # THRESHOLD = SPREAD.trade_costs()
        # CONDITIONAL_ORDER = SIGNED_ORDER % (SPREAD.abs() > THRESHOLD)
        # UNWIND_CONDITIONAL_ORDER = CONDITIONAL_ORDER.unwind() % (SPREAD * CONDITIONAL_ORDER.sign() > THRESHOLD)

        # PAIRED_ORDER = CONDITIONAL_ORDER.on_complete(UNWIND_CONDITIONAL_ORDER)

    async def validate_risk_monitor(self):
        print("[TEST SUITE] Starting Risk Monitor tests...")
        # ---- Simple Net Position offest check 1 - 1 ----
        # Note this is an edge case that checks we arent printing money
        # MKT vs MKT should be impossible for any trader to realise a net profit / loss
        # as they will be settled back at the midprice
        MKT_BUY = self.RITC.to_order(qty=30, order_type='MKT')
        # Cast the security to the bot's exchange connection and create an order
        MKT_SELLS = [
            -1 *
            self.RITC.assign_trader(bot).to_order(qty=10, order_type='MKT')
            for bot in self.bots
        ]

        # Make sure all orders are executed
        await self.assert_order_execution(MKT_BUY, *MKT_SELLS)

        # Check that sum of bot net positions = -1 trader net position
        net_bot_positions = sum([bot._risk.net_position for bot in self.bots])
        bot_pnls = sum([bot._risk.pnl for bot in self.bots])

        net_trader_position = self.trader._risk.net_position
        trader_pnl = self.trader._risk.pnl

        assert (net_trader_position == -1 * net_bot_positions)
        assert (trader_pnl == 0)
        assert (bot_pnls == 0)

        print("[TEST] Net Positions & PnL Basic Matching: Success")

        # ---- Simple Net Position offest check 1 - 1 in a MOVING market----
        # If the previous test no one could make money or lose money as
        # they simply settled at the market midprice which hadn't changed
        # Now we will move the market by 1 point and the onls should be symmetric

        # The limit orders will shift the best bid best ask by 1 after the same transactions
        # as previous where completed
        LMT_BUY = self.RITC.assign_trader(self.mopup_bot).to_order(
            qty=30, order_type='LMT', price_fn=improve_on_best_quote(-1))
        LMT_SELL = -1 * self.RITC.assign_trader(self.mopup_bot).to_order(
            qty=30, order_type='LMT', price_fn=improve_on_best_quote(1))

        # Make sure all orders are executed
        async def check_pnls():
            await asyncio.sleep(1)  # Ensures the market moving orders
            # have been executed first
            # NOTE I did have an issue when i shortened this sleep
            # so this is a hack for sure
            # but its not something we normally would do in the course of trading
            # so it should be fine.

            # Check that sum of bot net positions = -1 trader net position
            net_bot_positions = sum(
                [bot._risk.net_position for bot in self.bots])
            bot_pnls = sum([bot._risk.pnl for bot in self.bots])

            net_trader_position = self.trader._risk.net_position
            trader_pnl = self.trader._risk.pnl

            assert (net_trader_position == -1 * net_bot_positions)
            assert (trader_pnl == -1 * bot_pnls)
            assert (trader_pnl != 0)
            assert (self.trader._risk.realised == 0)

            print("[TEST] Net Positions & PnL Basic Moving Market: Success")

            # ---- Realised PNL Check ----
            # Now that we have non zero pnls we want to realise 1/2 of it
            # and check that realised pnl's are correct (50 50 split)

            # Since the market orders came earlier than the limit
            # which raised the bid the bot traders will take the hit to
            # there realised pnl

            # First we need to mopup those limits so they don't get in the way
            MKT_BUY = self.RITC.assign_trader(self.mopup_bot).to_order(
                qty=30, order_type='MKT')
            MKT_SELL = -1 * self.RITC.assign_trader(self.mopup_bot).to_order(
                qty=30, order_type='MKT')

            await self.assert_order_execution(MKT_BUY, MKT_SELL)

            # Now Lets sell half the traders stock
            MKT_SELL = -1 * self.RITC.to_order(qty=15, order_type='MKT')
            MKT_BUYS = [
                self.RITC.assign_trader(bot).to_order(qty=5, order_type='MKT')
                for bot in self.bots
            ]

            await self.assert_order_execution(MKT_SELL, *MKT_BUYS)

            # Checks the realised risk and unrealised has been split correctly
            assert (self.trader._risk.realised == self.trader._risk.unrealised)
            assert (self.trader._risk.realised != 0)
            assert (self.trader._risk.pnl == trader_pnl)

            last_bots_pnl = bot_pnls
            bots_realised = sum([bot._risk.realised for bot in self.bots])
            bots_unrealised = sum([bot._risk.unrealised for bot in self.bots])
            bot_pnls = sum([bot._risk.pnl for bot in self.bots])

            assert (bots_realised == bots_unrealised)
            assert (bot_pnls != 0)
            assert (bot_pnls == last_bots_pnl)

            print(
                "[TEST] Realised and unrealised pnl working as expected: Success"
            )

            MKT_SELL = -1 * self.RITC.to_order(qty=15, order_type='MKT')
            MKT_BUY = self.RITC.assign_trader(self.mopup_bot).to_order(
                qty=15, order_type='MKT')

            await self.assert_order_execution(
                MKT_SELL, MKT_BUY
            )  # now get rid of the traders remaining stock and close out position

        await asyncio.gather(self.assert_order_execution(LMT_BUY, LMT_SELL),
                             check_pnls())

        print("[TEST SUITE] Finished Risk Monitor Tests...")

    async def visual_inspection_test(self):
        UNDERLYINGS = self.BEAR + self.BULL
        SPREAD = self.RITC - self.USD * UNDERLYINGS

        # # Test Visual 1
        # LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1))
        # MKT_ORDER = -1 * self.RITC.to_order(qty=100, order_type='MKT')

        # assert(all(await asyncio.gather(MKT_ORDER.execute_later(5), LMT_ORDER.execute())))

        # # Test Visual 2
        # LMT_ORDER = SPREAD.to_order(qty=100, order_type='MKT')
        # MKT_ORDER = -1 * SPREAD.to_order(qty=100, order_type='MKT')

        # assert(all(await asyncio.gather(MKT_ORDER.execute_later(5), LMT_ORDER.execute())))

        # # Test 3 Present Single Limit Order
        # LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1))
        # await LMT_ORDER.execute()

        # Test 4 Table Scrolling
        # LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1))
        # LMT_ORDER_2 = -1*self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1))
        # # Then check order fill qtys working visually
        # MKT_ORDER = self.RITC.to_order(qty=50, order_type='MKT')

        # await self.assert_order_execution(*([LMT_ORDER]*20 + [LMT_ORDER_2]*20), MKT_ORDER)

        # Test 5 Market Dashboard
        MKT_ORDER = SPREAD.to_order(qty=50, order_type='MKT')
        LMT_ORDER = self.RITC.to_order(qty=50,
                                       order_type='LMT',
                                       price_fn=improve_on_best_quote(1))
        LMT_ORDER_2 = self.RITC.to_order(qty=50,
                                         order_type='LMT',
                                         price_fn=improve_on_best_quote(2))
        LMT_ORDER_3 = -1 * self.RITC.to_order(
            qty=50, order_type='LMT', price_fn=improve_on_best_quote(1))

        # # Then check order fill qtys working visually
        MKT_ORDER_2 = -1 * self.RITC.to_order(qty=50, order_type='MKT')
        MKT_ORDER_3 = -1 * self.RITC.to_order(qty=23, order_type='MKT')

        await self.assert_order_execution(
            *([LMT_ORDER] * 20 + [LMT_ORDER_2] * 20 + [MKT_ORDER] * 20 +
              [LMT_ORDER_3] * 25), MKT_ORDER_2, MKT_ORDER_3)

        print('[TEST] Visual Tests Complete!'
              )  # Obviously not going to get called :)
        # As we didnt square the position above

    def validate_product_display(self):
        SPREAD = self.RITC - self.USD * self.BEAR * self.BULL
        self.trader.register_product(SPREAD)

    async def connect_traders(self):
        await asyncio.gather(self.trader.connect_to_server(),
                             *[bot.connect_to_server() for bot in self.bots],
                             self.mopup_bot.connect_to_server())

    def configure_securities(self):
        self.RITC = Security('RITC', self.trader)
        self.BEAR = Security('BEAR', self.trader)
        self.BULL = Security('BULL', self.trader)
        self.USD = Security('USD', self.trader)

    async def run_tests(self):
        await asyncio.sleep(0.5)  # Let connection configure
        self.configure_securities()

        print('[Tests] Starting...')
        self.validate_product_display()
        # await asyncio.gather(self.validate_graph_pricing(),self.validate_pricing_functions(), self.validate_mkt_order_execution())
        # await asyncio.gather(self.visual_inspection_test())

        # NOTE the validate_mkt_order_execution will mess up
        # validate risk monitor as it makes the bid ask spread
        # invert which is not going to produce expected results :)
        # TODO: Implement prevent self trades [This will be incompatible with validate_mkt_order_execution] but in real trading environment we should stop this from happening
        # We will need to decide how best to catch these double sided entries...
        await self.validate_risk_monitor()

    async def run_script(self):
        await asyncio.gather(self.connect_traders(), self.run_tests())
Esempio n. 6
0
from frontend import Security, ExchangeConnection
import asyncio

EXCHANGE = ExchangeConnection()

RITC = Security('RITC', EXCHANGE)
BEAR = Security('BEAR', EXCHANGE)
BULL = Security('BULL', EXCHANGE)
USD = Security('USD', EXCHANGE)

UNDERLYINGS = BEAR + BULL
SPREAD = RITC - USD * UNDERLYINGS
SPREAD_USD_EXPSOURE = RITC * USD
HEDGED_SPREAD = SPREAD - SPREAD_USD_EXPSOURE

ORDER = HEDGED_SPREAD.to_order(qty=100, order_type="MKT")
SIGNED_ORDER = SPREAD.inv_sign() * ORDER

THRESHOLD = SPREAD.trade_costs()

CONDITIONAL_ORDER = SIGNED_ORDER % (SPREAD.abs() > THRESHOLD)

UNWIND_CONDITIONAL_ORDER = CONDITIONAL_ORDER.unwind() % (
    SPREAD * CONDITIONAL_ORDER.sign() > THRESHOLD)
PAIRED_ORDER = CONDITIONAL_ORDER.on_complete(UNWIND_CONDITIONAL_ORDER)

loop = asyncio.get_event_loop()

strategies = asyncio.gather(PAIRED_ORDER.execute_on_interval())
core = asyncio.gather(EXCHANGE.connect_to_server())
trading_system = asyncio.gather(core, strategies)
Esempio n. 7
0
 def __init__(self, enable_app=False, name='not_implemented'):
     ABC.__init__(self)
     self._connection_established = asyncio.Event()
     self._exchange_connection = ExchangeConnection(enable_app=enable_app, name=name, setup_event = self._connection_established)
     self._securities = {}