Пример #1
0
    async def brew(self, ctx, *indices):
        """Combine up to 3 ingredients to create a potion with deterministic properties depending on the ingredients used. The ingredients are consumed."""
        character = self.get(ctx.author)
        ingredients = []

        if character.profession != 'alchemist':
            return

        workshop_channel = self.bot.get_channel(workshop_channel_id)

        if len(indices) < 1 or len(indices) > 3:
            await ctx.author.send(
                utilities.yellow(
                    'You must provide 1-3 ingredients by inventory position to brew a potion.'
                ))
            return

        try:
            for index in [int(x) for x in indices]:
                ing = character.inventory[index]

                if ing.itype != 12:
                    await ctx.author.send(
                        utilities.red(f'{ing.name} is not an ingredient.'))
                    return

                if ing.level > character.level:
                    await ctx.author.send(
                        utilities.yellow(
                            'You are not experienced enough to work with these ingredients.'
                        ))
                    return

                ingredients.append(ing)
        except IndexError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))

        consumable = create_consumable(ingredients)

        if consumable is False:
            await workshop_channel.send(
                utilities.yellow(
                    'You must provide 1-3 ingredients by inventory position to brew a potion.'
                ))
            return

        consumable.description = consumable.description.replace(
            '|', character.name)
        consumable.save()

        for ing in ingredients:
            character.remove_from_inventory(ing)

        character.add_to_inventory(consumable, True)
        await workshop_channel.send(
            f'{ctx.author.name} brewed: {consumable.name}.')
Пример #2
0
 def _delete(self, msg):
     if not self.partial:
         raise NoPartial("Cant init the book, not partials in")
     for item in msg:
         #flt pt red
         item = red(item)
         del self.book[item['id']]
Пример #3
0
    async def withdraw(self, ctx, index: int):
        """Add an item from your bank to your inventory. This action costs 1 coin per item in your bank account."""
        character = self.get(ctx.author)

        try:
            name = character.bank[index].name
        except IndexError:
            await ctx.author.send(utilities.red('Invalid bank position.'))
            return

        if character.coins < len(character.bank):
            await ctx.author.send(utilities.yellow(f'You need {len(character.bank)} coins to pay your withdrawal fee.'))
        elif character.withdraw(index):
            await ctx.channel.send(f'{character.name} withdrew {name} from the bank.')
        else:
            await ctx.author.send(utilities.red(f'Unable to withdraw an item. You may be at maximum carry weight.'))
Пример #4
0
    async def socket(self, ctx, item_index: int, gemstone_index: int):
        """Socket a gemstone into an unequipped weapon or armor in your inventory with an open socket. The change is irreversible. You must be a Jeweler to use this crafting option."""
        character = self.get(ctx.author)

        if character.profession != 'jeweler':
            return

        workshop_channel = self.bot.get_channel(workshop_channel_id)
        gem = None
        item = None

        try:
            gem = character.inventory[gemstone_index]
            item = character.inventory[item_index]

            if gem.itype != 11:
                await ctx.author.send(utilities.red('That is not a gemstone.'))
                return
            if item.itype not in [1, 2, 3, 5, 6]:
                await ctx.author.send(
                    utilities.red('That is not a socketable item.'))
                return
        except IndexError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))

        if character.level < gem.level:
            await ctx.author.send(
                utilities.yellow(
                    'You are not experienced enough to work with this quality of gem.'
                ))
            return

        if not gemstone.usable_in(gem, item):
            await ctx.author.send(
                utilities.yellow(
                    f'{gem.name} cannot be applied to this item type.'))
            return

        if socket_gemstone(item, gem):
            character.remove_from_inventory(gem)
            await workshop_channel.send(
                f'{ctx.author.name} improved their {item.name}, adding: {gem.name}.'
            )
        else:
            await ctx.author.send(
                utilities.yellow(f'{item.name} has no open sockets.'))
Пример #5
0
 def _insert(self, msg):
     if not self.partial:
         raise NoPartial("Cant init the book, no partials in")
         # unpack list
     for item in msg:
         # flt point change
         item = red(item)
         self.book[item.pop('id')] = item
Пример #6
0
    async def prepare(self, ctx, index: int, slot: int):
        """Prepare a known ability, assigning it to an action slot (1-6) for use in fights."""
        character = self.get(ctx.author)

        if character.assign_ability_to_slot(index, slot):
            await ctx.author.send(f'Ability prepared in slot {slot}.')
        else:
            await ctx.author.send(
                utilities.red('Invalid ability index or slot.'))
Пример #7
0
    async def player_dead(self, delve, character):
        character.unequip_all()
        character.inventory = []
        character.current_carry = 0
        character.deaths += 1
        character.reset_stats()
        character.save()
        await delve.channel.send(
            utilities.red('{} has died.'.format(character.name)))

        if len(delve.players) == 1:
            await delve.channel.send(utilities.red('Thus ends the delve.'))
            self.delves.pop(delve.channel.name)
            await asyncio.sleep(3)
            await delve.channel.delete()
        else:
            for player in delve.players:
                if str(player) == character.name:
                    await delve.remove_player(character)
Пример #8
0
    async def ability(self, ctx, index=0):
        """Show the details of a specific ability known to your character."""
        character = self.get(ctx.author)

        try:
            await ctx.author.send(
                utilities.ability_to_str(character.abilities[index],
                                         character.level))
        except IndexError:
            await ctx.author.send(utilities.red('Invalid ability index.'))
Пример #9
0
    async def use(self, ctx, index: int):
        character = self.get(ctx.author)

        try:
            consumable = character.inventory[index]
        except IndexError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))
            return

        await ctx.channel.send(character.use_consumable(consumable))
Пример #10
0
 def _partial(self, msg):
     """
     fucntion to initialize the book at partial
     :param msg: list of dict
     :return: nothing
     """
     for item in msg:
         self.book[item['id']] = dict(side=item['side'],
                                         price=red(item['price']),
                                         size=item['size'])
     self.partial = True
Пример #11
0
    async def unequip(self, ctx, slot):
        """Unequips the item from your gear in the specified slot."""
        if slot not in weapon.valid_slots:
            await ctx.author.send(utilities.red('Invalid gear slot.'))
        else:
            character = self.get(ctx.author)
            item = character.unequip(slot)

            if item is not None:
                await ctx.author.send(
                    f'{utilities.underline(item.name)} unequipped.')
Пример #12
0
    async def offer(self, ctx, index: int):
        """Ask how much the NPC vendor will pay for an item in your inventory."""
        character = self.get(ctx.author)

        try:
            item = character.inventory[index]
            n = item.name  # TODO is this needed?
            offer = int(item.value * self.buy_rate)
            await ctx.channel.send(f'{self.name} says, "I\'d give you {offer} coins for your {n}, {character.name}."')
        except KeyError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))
Пример #13
0
    async def sell(self, ctx, index: int):
        """Sell an item to the NPC vendor. Sold item_specs cannot be bought back."""
        character = self.get(ctx.author)

        try:
            item = character.inventory[index]
            n = item.name  # TODO is this needed?
            offer = int(item.value * self.buy_rate)
            character.coins += offer
            character.remove_from_inventory(item, False)
            # item.delete()
            await ctx.channel.send(f'{character.name} sold {n} to {self.name} for {offer} coins."')
        except KeyError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))
Пример #14
0
    async def deposit(self, ctx, index: int):
        """Deposit an item into your bank from your inventory."""
        character = self.get(ctx.author)

        try:
            name = character.inventory[index].name
        except IndexError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))
            return

        if len(character.bank) >= character.bank_limit:
            await ctx.author.send(utilities.yellow(f'Your bank account is at the current limit of {character.bank_limit} item_specs.'))
        elif character.deposit(index):
            await ctx.channel.send(f'{character.name} deposited {name} to the bank.')
Пример #15
0
    def orders_sync(self, data, force=True):
        """
        in case of issue, we might want to re-sync the book. A typical case would be a trader reconnection, but we can also force an API call

        the assumption is that the data is right, but we:
        00. if we have an empty data, we do nothing
        0. in case of force=True, we need to filter by workingIndicator as we will get all orders. We also might need a Lock  as we're trading and stuff happens TODO think about it
        1. keep whatever matches for clOrdID, orderQty, symbol, price (market orders are gone in case of update anyway), but update qty if the three match
        2. if something remains, create orders accordingly
        2. if some orders are still there, they can be removed although we should query if they were in fact filled (for book consistency)
        :param data:
        :param force:
        :return:
        """

        if data != []:
            # do nothing otherwise
            if force:
                data = [x for x in data if x['workingIndicator'] == True]
            # we will compare subsets
            # flt pt issue conversion
            data = [red(x) for x in data]
            data = [{k: v for k, v in x.items() if k in ['clOrdID', 'orderQty', 'symbol', 'price', 'orderID']} for x in
                    data]
            # copy, not move in place (TODO is deepcopy required ?)
            keep = dict()
            # remaining orders from the ack

            remain = []
            for order in self.keep.values():  # TODO with dicts instead this is prob unencessarily convoluted
                intm_comp = {k: v for k, v in order.__dict__.items() if k in ['clOrdID', 'orderQty', 'symbol', 'price']}
                for ack_o in data:
                    if {k: v for k, v in ack_o.items() if k in ['clOrdID', 'symbol', 'price']} == {j: f for j, f in
                                                                                                   intm_comp.items() if
                                                                                                   ['clOrdID', 'symbol',
                                                                                                    'price']}:
                        # we compare ordQty, possibly adjust (and inform) and we copy for keep (order) and remain (ack element)
                        if ack_o['ordQty'] != order.orderQty:
                            self.debug("adjusting quantity from market for clOrdID {}".format(order.clOrdID))
                        keep[order.clOrdID] = order
            # now we should have a list of orders that matched/are adjusted
            self.keep = keep
            remain = [x for x in data if x['clOrdID'] not in [y.clOrdID for y in keep]]
            # if we have orders to add we add them as "processed"
            if remain != []:
                for x in remain:
                    x['status'] = 'processed'
                self.add_order(remain)
Пример #16
0
    def test_red(self):

        a = 1
        b = 3.7800000000000002e-06
        c = 0.1
        d = {'symbol': 'XBTUSD', 'id': 15599607950, 'side': 'Sell', 'size': 80, 'price': 3.7800000000000002e-06}
        e = (3.7800000000000002e-06, "b")
        f = [3.7800000000000002e-06, 3 , 4]

        bch_p = 0.030100000000000002
        self.assertEqual(red(bch_p), '0.0301')
        self.assertEqual(red(a), a)
        self.assertEqual(red(b), '3.78e-06')
        self.assertEqual(red(c), c)
        self.assertEqual(red(d), {'symbol': 'XBTUSD', 'id': 15599607950, 'side': 'Sell', 'size': 80, 'price': '3.78e-06'})
        self.assertEqual(red(e), ('3.78e-06', "b"))
        self.assertEqual(red(f), ['3.78e-06', 3, 4])

        self.assertEqual(dered(red(b)), 3.78e-06)
        self.assertEqual(dered(red(d)),
                         {'symbol': 'XBTUSD', 'id': 15599607950, 'side': 'Sell', 'size': 80, 'price': 3.78e-06})
        self.assertEqual(dered('871528a8-7d67-45d9-a9de-112e0da22ff4'), '871528a8-7d67-45d9-a9de-112e0da22ff4')
Пример #17
0
    async def equip(self, ctx, pos: int):
        """Attempts to equip the item from your inventory at the specified position. Will first unequip anything already equipped in that same slot."""
        character = self.get(ctx.author)

        try:
            item = character.inventory[pos]
        except IndexError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))
            return

        if item is not None:
            if character.equip(item):
                await ctx.author.send(
                    f'{utilities.underline(item.name)} equipped.')
            else:
                await ctx.author.send(
                    f'You do not meet the requirements to equip {item.name}.')
Пример #18
0
    def __init__(self, symbol, orderQty, price, id_level=None, ordType="Limit", execInst="ParticipateDoNotInitiate",
                 strat=None):

        self.clOrdID = str(uuid4())
        self.logger = logging.getLogger("Order {}".format(self.clOrdID[:4]))
        self.logger.setLevel(logging.DEBUG)
        self.orderID = None
        self.ts = None
        self.ts_exec = None  # this is for fills
        self.symbol = symbol
        self.ordType = ordType
        if self.ordType == "Market":
            self.price = None
            self.debug("discarding price for market order")
        else:
            # hook for float
            self.price = red(price)

        self.execInst = execInst
        self.orderQty = orderQty
        if self.orderQty > 0:
            self.side = 'Buy'
        elif self.orderQty < 0:
            self.side = 'Sell'
        else:
            raise InconsistentOrderData("Qty is wrong: {}".format(orderQty))

        self.status = 'new'  # 'processed' 'on_ladder' 'canceled'
        if id_level:
            self.id_level = id_level
        else:
            self.id_level = None

        self.size_before = None
        self.size_after = None
        # wait for my update how long
        self.saw_myself = False  # this is mostly for debugging purposes
        self.wait = 0.5  # seconds

        # trader action tracking
        self.ws_ack = False
        self.ws_working = False
        self.debug("alive with ordQty {}, price {}, status {}, lvl {}, orderID {}".format(self.orderQty,
                                                                                          self.price, self.status,
                                                                                          self.id_level, self.orderID))
Пример #19
0
    async def buy(self, ctx, index: int):
        """Buy a listed item from the NPC vendor."""
        character = self.get(ctx.author)

        try:
            item = character.shop[index]
            price = int(item.value * self.sell_rate)

            if character.coins >= price:
                if character.add_to_inventory(item, False):
                    character.coins -= price
                    character.shop.remove(item)
                    character.save()
                    await ctx.channel.send(f'{character.name} bought: {item.name}')
                else:
                    await ctx.author.send(utilities.yellow('You are carrying too much to buy that.'))
            else:
                await ctx.author.send(f'{self.name} informs you, sharply, that you are too poor to afford that.')
        except IndexError:
            await ctx.author.send(utilities.red('Invalid shop inventory position.'))
Пример #20
0
    def _update(self,msg):
        """
        updates the relevant level, found by price (dict.update)
        :param msg: list of dict(s)
        :return: if there's a callback returns stuff. Otherwise returns nothing
        """
        if not self.partial:
            raise NoPartial("Cant init the book, not partials in")
        #unpack list
        diffs = []
        for item in msg:
            # hook the float point conv
            item = red(item)
            k = item.pop('id')
            d = compare_and_update(self.book[k], item)
            d['id'] = k

            diffs.append(d)

        if self.callback:

            return self.callback(diffs)
Пример #21
0
    async def learn(self, ctx, index: int):
        """Consume a manual or tome to learn a new ability."""
        character = self.get(ctx.author)
        book = character.inventory[index]

        try:
            if character.learn(book):
                await ctx.author.send(
                    utilities.bold('You have learned a new ability!'))
                # book.delete()
                character.remove_from_inventory(book)
            else:
                await ctx.author.send(
                    utilities.yellow(
                        f'You are unable to learn anything by reading the {character.inventory[index]["name"]}.'
                    ))
        except IndexError:
            await ctx.author.send(utilities.red('Invalid inventory position.'))
        except KeyError:
            await ctx.author.send(
                utilities.yellow(
                    f'You find it difficult to read the {character.inventory[index]["name"]}.'
                ))
Пример #22
0
    def test_evaluate_outstanding_orders(self):
        """
        this is a tricky part. We want to test
        1. case with no removal
        2. case with removal of inside bid (or aks, or both) in case of q_pos with or without t_market
        2a. case of partial removal if we have inventory on the other side
        3. storage of said removal and automatic subsequent removal
        4. reset of removal on change of bbo
        :return:
        """
        # we only nneed one level and the return is the value straigh up # TODO API consistency would probably be better if OrderBOOK.bbo returned a list always but I dont want ot break stuff right now
        #self.mm.bbo.return_value = {'bid': '0.0281', 'ask' : '0.0286'} # TODO because of float point error (red / dered in utilities we can either have a float (XBTUSD eg or string) Not good
        cur_ob = self.mm.bbo()

        bid_post_pxs, ask_post_pxs = self.mm.calculate_quotes(
            0, 0, cur_ob['bid'][0], cur_ob['ask'][0])

        # sub case 1
        print("case 1:  no removal")
        # we fix the q_ratios at 281 and 286
        self.mm.order_report.return_value = {
            'bids': [{
                'symbol': 'BCHZ18',
                'price': str(0.0281 + i * 0.0001),
                'orderQty': 1,
                'clOrdID': 'ffbf6395-5ee4-445d-aa2c-6d34054dfd89',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 11.937583,
                'q_pos': self.mm.q_ratio_threshold - 0.1
            } for i in range(0, 10)],
            'asks': [{
                'symbol': 'BCHZ18',
                'price': str(0.0286 - i * 0.0001),
                'orderQty': -1,
                'clOrdID': '1c2490e2-0961-4c2d-b3e8-5987dfe534f4',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 11.937742,
                'q_pos': self.mm.q_ratio_threshold - 0.1
            } for i in range(0, 10)]
        }

        bid_post_pxs, ask_post_pxs = self.mm.evaluate_outstanding_orders(
            bid_post_pxs, ask_post_pxs)

        self.assertEqual(bid_post_pxs[0], 0.0281)
        self.assertEqual(ask_post_pxs[0], 0.0286)
        self.assertEqual(len(bid_post_pxs), 2 * self.mm.layer_depth)
        self.assertEqual(len(ask_post_pxs), 2 * self.mm.layer_depth)

        #sub case 2
        print("case 2:  no removal for grace period while q is bad")
        self.mm.order_report.return_value = {
            'bids': [
                {
                    'symbol': 'BCHZ18',
                    'price': str(0.0281 + i * 0.0001),
                    'orderQty': 1,
                    'clOrdID': 'ffbf6395-5ee4-445d-aa2c-6d34054dfd89',
                    'execInst': 'ParticipateDoNotInitiate',
                    't_market': 0.5,
                    'q_pos': self.mm.q_ratio_threshold + 0.1
                }  #t_market under grace time and q ratio bad
                for i in range(0, 10)
            ],
            'asks': [{
                'symbol': 'BCHZ18',
                'price': str(0.0286 - i * 0.0001),
                'orderQty': -1,
                'clOrdID': '1c2490e2-0961-4c2d-b3e8-5987dfe534f4',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 0.5,
                'q_pos': self.mm.q_ratio_threshold + 0.1
            } for i in range(0, 10)]
        }
        bid_post_pxs, ask_post_pxs = self.mm.calculate_quotes(
            0, 0, cur_ob['bid'][0], cur_ob['ask'][0])

        bid_post_pxs, ask_post_pxs = self.mm.evaluate_outstanding_orders(
            bid_post_pxs, ask_post_pxs)

        self.assertEqual(bid_post_pxs[0], 0.0281)
        self.assertEqual(ask_post_pxs[0], 0.0286)
        self.assertEqual(len(bid_post_pxs), 2 * self.mm.layer_depth)
        self.assertEqual(len(ask_post_pxs), 2 * self.mm.layer_depth)

        print("case 2:  removal  while q is bad, both side")
        self.mm.last_bbo = None
        self.mm.order_report.return_value = {
            'bids': [
                {
                    'symbol': 'BCHZ18',
                    'price': str(0.0281 + i * 0.0001),
                    'orderQty': 1,
                    'clOrdID': 'ffbf6395-5ee4-445d-aa2c-6d34054dfd89',
                    'execInst': 'ParticipateDoNotInitiate',
                    't_market': 10,
                    'q_pos': self.mm.q_ratio_threshold + 0.1
                }
                # t_market under grace time and q ratio bad
                for i in range(0, 10)
            ],
            'asks': [{
                'symbol': 'BCHZ18',
                'price': str(0.0286 - i * 0.0001),
                'orderQty': -1,
                'clOrdID': '1c2490e2-0961-4c2d-b3e8-5987dfe534f4',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 10,
                'q_pos': self.mm.q_ratio_threshold + 0.1
            } for i in range(0, 10)]
        }
        bid_post_pxs, ask_post_pxs = self.mm.calculate_quotes(
            0, 0, cur_ob['bid'][0], cur_ob['ask'][0])
        # print(cur_ob)
        bid_post_pxs, ask_post_pxs = self.mm.evaluate_outstanding_orders(
            bid_post_pxs, ask_post_pxs)
        # print("bids: {} \n asks: {}".format(bid_post_pxs, ask_post_pxs))
        print("new inside")
        self.assertEqual(bid_post_pxs[0], 0.028)
        self.assertEqual(ask_post_pxs[0], 0.0287)
        print(self.mm.last_bbo)
        self.assertEqual({
            'bid': '0.0281',
            'ask': '0.0286'
        }, red(self.mm.last_bbo))  # TODO is it wise ?
        self.assertNotEqual(ask_post_pxs[0], 0.0286)
        self.assertNotEqual(bid_post_pxs[0], 0.0281)
        self.assertEqual(len(bid_post_pxs), 2 * self.mm.layer_depth - 1)
        self.assertEqual(len(ask_post_pxs), 2 * self.mm.layer_depth - 1)

        print(
            "case 2:  removal  while q is good but last_bbo exists, both side")
        self.mm.order_report.return_value = {
            'bids': [
                {
                    'symbol': 'BCHZ18',
                    'price': str(0.0281 + i * 0.0001),
                    'orderQty': 1,
                    'clOrdID': 'ffbf6395-5ee4-445d-aa2c-6d34054dfd89',
                    'execInst': 'ParticipateDoNotInitiate',
                    't_market': 10,
                    'q_pos': self.mm.q_ratio_threshold - 0.1
                }
                # t_market under grace time and q ratio bad
                for i in range(0, 10)
            ],
            'asks': [{
                'symbol': 'BCHZ18',
                'price': str(0.0286 - i * 0.0001),
                'orderQty': -1,
                'clOrdID': '1c2490e2-0961-4c2d-b3e8-5987dfe534f4',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 10,
                'q_pos': self.mm.q_ratio_threshold - 0.1
            } for i in range(0, 10)]
        }
        #settign up last bbo here
        print("set last_bbo")
        self.mm.last_bbo = {'bid': 0.0281, 'ask': 0.0286}
        self.mm.get_inventory.return_value = 0
        bid_post_pxs, ask_post_pxs = self.mm.calculate_quotes(
            0, 0, cur_ob['bid'][0], cur_ob['ask'][0])

        bid_post_pxs, ask_post_pxs = self.mm.evaluate_outstanding_orders(
            bid_post_pxs, ask_post_pxs)
        # print("bids: {} \n asks: {}".format(bid_post_pxs, ask_post_pxs))
        self.assertEqual(bid_post_pxs[0], 0.028)
        self.assertEqual(ask_post_pxs[0], 0.0287)
        self.assertEqual({
            'bid': '0.0281',
            'ask': '0.0286'
        }, red(self.mm.last_bbo))  # TODO is it wise ?
        self.assertNotEqual(ask_post_pxs[0], 0.0286)
        self.assertNotEqual(bid_post_pxs[0], 0.0281)
        self.assertEqual(len(bid_post_pxs), 2 * self.mm.layer_depth - 1)
        self.assertEqual(len(ask_post_pxs), 2 * self.mm.layer_depth - 1)

        print(
            "case 2a:  removal  while q is good but last_bbo exists, both side but I have pos inventory"
        )
        self.mm.order_report.return_value = {
            'bids': [
                {
                    'symbol': 'BCHZ18',
                    'price': str(0.0281 + i * 0.0001),
                    'orderQty': 1,
                    'clOrdID': 'ffbf6395-5ee4-445d-aa2c-6d34054dfd89',
                    'execInst': 'ParticipateDoNotInitiate',
                    't_market': 10,
                    'q_pos': self.mm.q_ratio_threshold - 0.1
                }
                # t_market under grace time and q ratio bad
                for i in range(0, 10)
            ],
            'asks': [{
                'symbol': 'BCHZ18',
                'price': str(0.0286 - i * 0.0001),
                'orderQty': -1,
                'clOrdID': '1c2490e2-0961-4c2d-b3e8-5987dfe534f4',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 10,
                'q_pos': self.mm.q_ratio_threshold - 0.1
            } for i in range(0, 10)]
        }
        # positive inv so, I only want to deal with inside bid
        self.mm.get_inventory.return_value = 10
        # settign up last bbo here
        print("set last_bbo")
        self.mm.last_bbo = {'bid': 0.0281, 'ask': 0.0286}
        bid_post_pxs, ask_post_pxs = self.mm.calculate_quotes(
            0, 0, cur_ob['bid'][0], cur_ob['ask'][0])
        print(bid_post_pxs)
        print(ask_post_pxs)
        bid_post_pxs, ask_post_pxs = self.mm.evaluate_outstanding_orders(
            bid_post_pxs, ask_post_pxs)
        print("bids: {} \n asks: {}".format(bid_post_pxs, ask_post_pxs))
        self.assertEqual(bid_post_pxs[0], 0.028)
        self.assertEqual(ask_post_pxs[0], 0.0286)
        self.assertEqual({
            'bid': '0.0281',
            'ask': '0.0286'
        }, red(self.mm.last_bbo))  # TODO is it wise ?
        self.assertNotEqual(ask_post_pxs[0], 0.0287)
        self.assertNotEqual(bid_post_pxs[0], 0.0281)
        self.assertEqual(len(bid_post_pxs), 2 * self.mm.layer_depth - 1)
        self.assertEqual(len(ask_post_pxs), 2 * self.mm.layer_depth)

        print("case 3:  change of BBO unsets last_bbo")
        self.mm.order_report.return_value = {
            'bids': [
                {
                    'symbol': 'BCHZ18',
                    'price': str(0.0281 + i * 0.0001),
                    'orderQty': 1,
                    'clOrdID': 'ffbf6395-5ee4-445d-aa2c-6d34054dfd89',
                    'execInst': 'ParticipateDoNotInitiate',
                    't_market': 0.5,
                    'q_pos': self.mm.q_ratio_threshold - 0.1
                }
                # t_market under grace time and q ratio bad
                for i in range(0, 10)
            ],
            'asks': [{
                'symbol': 'BCHZ18',
                'price': str(0.0286 - i * 0.0001),
                'orderQty': -1,
                'clOrdID': '1c2490e2-0961-4c2d-b3e8-5987dfe534f4',
                'execInst': 'ParticipateDoNotInitiate',
                't_market': 0.5,
                'q_pos': self.mm.q_ratio_threshold - 0.1
            } for i in range(0, 10)]
        }
        # settign up last bbo here
        print("set last_bbo")
        self.mm.last_bbo = {'bid': '0.0281', 'ask': '0.0286'}
        self.mm.bbo.return_value = {
            'bid': [
                0.028, 0.0279, 0.0275, 0.0273, 0.0272, 0.0271, 0.027, 0.0269,
                0.0268, 0.0267, 0.0266, 0.0265, 0.0264, 0.026, 0.0255, 0.025,
                0.0249, 0.0233, 0.02
            ],
            'ask': [
                0.0287, 0.0288, 0.029, 0.0294, 0.0295, 0.0296, 0.0297, 0.0298,
                0.0299, 0.03, 0.0301, 0.0302, 0.0303, 0.0324, 0.0371, 0.0383,
                0.0417, 0.0433, 0.0442
            ]
        }

        self.mm.get_inventory.return_value = 0
        bid_post_pxs, ask_post_pxs = self.mm.calculate_quotes(
            0, 0,
            self.mm.bbo()['bid'][0],
            self.mm.bbo()['ask'][0])  # NOTE the call is a bit different here
        print(bid_post_pxs)
        bid_post_pxs, ask_post_pxs = self.mm.evaluate_outstanding_orders(
            bid_post_pxs, ask_post_pxs)
        # print("bids: {} \n asks: {}".format(bid_post_pxs, ask_post_pxs))
        self.assertEqual(0.028, bid_post_pxs[0])
        self.assertEqual(0.0287, ask_post_pxs[0])
        self.assertIsNone(self.mm.last_bbo)
Пример #23
0
    async def level(self, ctx):
        """Consumes a level point, allowing you to choose from a set of improvements to your character."""
        character = self.get(ctx.author)

        if character.points <= 0:
            await ctx.author.send(
                utilities.red('You do not have any available level points.'))
        else:
            if character.level % 5 == 4:
                await ctx.author.send(character.display_level_up_menu(True))

                def check_level_up_menu_selection(m):
                    if str(m.author) == character.name and m.content in [
                            '1', '2', '3', '4', '5', '6'
                    ]:
                        return True

                try:
                    msg = await self.bot.wait_for(
                        'message',
                        check=check_level_up_menu_selection,
                        timeout=30)
                    choice = int(msg.content)
                except asyncio.TimeoutError:
                    await ctx.author.send(
                        utilities.yellow(
                            'Selection timed out. Please use \\level again when you are ready.'
                        ))
                    return

                if choice == 1:
                    character.earth_res += 0.01
                    await ctx.author.send(
                        'Your earth resistance has been permanently increased by 1%.'
                    )
                elif choice == 2:
                    character.fire_res += 0.01
                    await ctx.author.send(
                        'Your fire resistance has been permanently increased by 1%.'
                    )
                elif choice == 3:
                    character.electricity_res += 0.01
                    await ctx.author.send(
                        'Your electricity resistance has been permanently increased by 1%.'
                    )
                elif choice == 4:
                    character.water_res += 0.01
                    await ctx.author.send(
                        'Your water resistance has been permanently increased by 1%.'
                    )
                elif choice == 5:
                    character.dot_res += 0.03
                    await ctx.author.send(
                        'Your damage over time resistance has been permanently increased by 3%.'
                    )
                elif choice == 6:
                    character.dot_effect += 0.03
                    await ctx.author.send(
                        'Your damage over time effectiveness has been permanently increased by 3%.'
                    )
                else:
                    await ctx.channel.send(
                        utilities.red(
                            f'Invalid level up reward selection {msg}.'))
                    return
            else:
                await ctx.author.send(character.display_level_up_menu(False))

                def check_level_up_menu_selection(m):
                    if str(m.author) == character.name and m.content in [
                            '1', '2', '3', '4', '5', '6', '7'
                    ]:
                        return True

                try:
                    msg = await self.bot.wait_for(
                        'message',
                        check=check_level_up_menu_selection,
                        timeout=30)
                    choice = int(msg.content)
                except asyncio.TimeoutError:
                    await ctx.author.send(
                        utilities.yellow(
                            'Selection timed out. Please use \\level again when you are ready.'
                        ))
                    return

                if choice == 1:
                    character.strength += 3
                    await ctx.author.send(
                        'Your base strength has been permanently increased by 3.'
                    )
                elif choice == 2:
                    character.intelligence += 3
                    await ctx.author.send(
                        'Your base intelligence has been permanently increased by 3.'
                    )
                elif choice == 3:
                    character.dexterity += 3
                    await ctx.author.send(
                        'Your base dexterity has been permanently increased by 3.'
                    )
                elif choice == 4:
                    character.willpower += 3
                    await ctx.author.send(
                        'Your base willpower has been permanently increased by 3.'
                    )
                elif choice == 5:
                    character.health += 5
                    await ctx.author.send(
                        'Your base health has been permanently increased by 5.'
                    )
                elif choice == 6:
                    character.stamina += 5
                    await ctx.author.send(
                        'Your base stamina has been permanently increased by 5.'
                    )
                elif choice == 7:
                    character.mana += 5
                    await ctx.author.send(
                        'Your base mana has been permanently increased by 5.')
                else:
                    await ctx.channel.send(
                        utilities.red(
                            f'Invalid level up reward selection {msg}.'))
                    return

            character.points -= 1
            character.level += 1
            character.save()
            items = []

            for _ in range(2):
                items.append(
                    generate_random_item(character.level,
                                         rarity=Rarity.common))
                items.append(generate_random_book(character.level))

            character.restock(items)
            await ctx.channel.send(
                utilities.green(f'{character.name} has grown in power!'))
Пример #24
0
    def agent_perform(self, indi_dict, curr_inventory):
        """
        :param indi_dict: dict of indi values
        :param curr_inventory : int of inventory level
        :return:
        """
        self.debug('in agent perform with state: {}'.format(self.agent_state))

        if not indi_dict['current_ob'] or indi_dict['current_ob'][
                'bid'] == [] or indi_dict['current_ob']['ask'] == []:
            bid_px = ask_px = None
        else:
            bid_px = indi_dict['current_ob']['bid'][0]
            ask_px = indi_dict['current_ob']['ask'][0]

        if self.agent_state == 'INIT':
            pass
        elif self.agent_state == 'KILL':
            self.logger.critical('KILL STATE - LOST MAX STOP LINE!')
            # todo need panic close

        # get the basic skew
        bid_skew, ask_skew = self.skew_ticks()
        # update desired lists of bids and asks
        bid_post_pxs, ask_post_pxs = self.calculate_quotes(bid_skew=bid_skew,
                                                           ask_skew=ask_skew,
                                                           bid_px=bid_px,
                                                           ask_px=ask_px)

        # we sort the prices for convenience:
        bid_post_pxs = sorted(bid_post_pxs, reverse=True)
        ask_post_pxs = sorted(ask_post_pxs)

        # now we remove the closest inside bid if trade ratio is not our way
        if self.agent_state in ['DUAL', 'BID']:
            if indi_dict['trade_ratio'] < self.trade_dir_ratio_thresh:
                if bid_post_pxs:
                    # remove the closest ask
                    bid_post_pxs.pop(0)

        if self.agent_state in ['DUAL', 'ASK']:
            # 1 way trades incoming
            if indi_dict['trade_ratio'] > 1 - self.trade_dir_ratio_thresh:
                if ask_post_pxs:
                    # remove the closest ask
                    ask_post_pxs.pop(0)

        bid_post_pxs, ask_post_pxs = self.evaluate_outstanding_orders(
            ask_post_pxs=ask_post_pxs, bid_post_pxs=bid_post_pxs)

        # we truncate both sides to the number of orders we want
        bid_post_pxs = bid_post_pxs[:self.layer_depth]
        # we hook the red function here
        bid_post_pxs = red(bid_post_pxs)
        ask_post_pxs = ask_post_pxs[:self.layer_depth]
        ask_post_pxs = red(ask_post_pxs)
        bid = [
            dict(symbol=self.symbol_list[0], orderQty=self.quote_size, price=x)
            for x in bid_post_pxs if x is not None
        ]
        ask = [
            dict(symbol=self.symbol_list[0],
                 orderQty=-self.quote_size,
                 price=x) for x in ask_post_pxs if x is not None
        ]

        # Inventory checks
        if curr_inventory >= self.max_inventory:
            bid = [None]

        if curr_inventory <= -self.max_inventory:
            ask = [None]

        to_exec = bid + ask
        to_exec = [x for x in to_exec if x is not None]

        # bonus, if our inventory is over 50% of mx inventory, scratch it
        cur_inv = self.get_inventory()
        avg_px = self.get_inv_avg_px()
        last_trades = self.request_trades(n=1)
        if last_trades:
            last_price = last_trades[0]['price']

        if last_trades and abs(cur_inv) > 0.5 * self.max_inventory and abs(
                last_price / avg_px -
                1) > 0.01:  # TODO harcoded ratios are not nice

            to_exec.append(
                dict(symbol=self.symbol_list[0],
                     orderQty=-cur_inv,
                     ordType='Market'))

        self.execute(to_exec)
Пример #25
0
    def evaluate_outstanding_orders(self, bid_post_pxs, ask_post_pxs):
        """

        compare are naive skewed quote against outstanding orders and our current best bid/ask

        update: we want to burn the BBO and only the BBO if we don't get the queue, but only opposite side if we carry an invetory
        :param order_stats: list dict
        :param bid_px= float
        :param ask_px = float
        :param bid_post_pxs = list
        :param ask_post_pxs = list
        :return: tuple of lists
        """

        # we get the order report with q times and time on market. The time on market should not be a problem for Q size
        # since orderKeep pushes a ladder value after some time if we miss some messages (Order.saw_myself = False)
        # the order report (OrderKeep.exec_report) returns a dict of bids and ask keys with lists in descending order of
        # closeness to the mid-price
        # update, at this point the bid_ps /ask_ px should be floats

        # so now we check if we have a previously burnt BBO

        if self.last_bbo:
            # if we do, has it moved
            cur_bbo = {k: v[0] for k, v in self.bbo(lvl=5).items()}
            self.debug("last bbo {} | cur bbo {}".format(
                self.last_bbo, cur_bbo))
            # TODO this is a bit ugly but since I have an inconsistent API for OrderBOOK.get_bbo for lvl=1 and lvl >1 that's that for now

            if red(self.last_bbo) != red(cur_bbo):
                # if so, we reset
                self.last_bbo = None
            # esle it means we have canceled an order at the ask or bid already so we'll match that price to remove it later

        cur_orders = self.order_report()

        # we get ack to float
        cur_orders = {k: dered(v) for k, v in cur_orders.items()}
        self.debug("q & prices : bids {} \n asks {}".format([{
            k: v
            for k, v in x.items() if k in ['price', 'q_pos', 't_market']
        } for x in cur_orders['bids']], [{
            k: v
            for k, v in x.items() if k in ['price', 'q_pos', 't_market']
        } for x in cur_orders['asks']]))
        # we check that we are not holding the bag (after a grace period of self.grace_time_q) for the
        # first (n) levels and remove if so
        if (cur_orders['bids'] != []
                or cur_orders['asks'] != []) and self.bbo(lvl=5) and self.bbo(
                    lvl=5).get('bid') and self.bbo(lvl=5).get('ask'):
            # we check if we have inventory
            #
            # we id our best bid and best ask orders
            #print("in flicker loop")
            self.debug("cur orders {}".format(cur_orders))
            flt_fun = lambda x: float(x['price'])
            try:
                bb = sorted(cur_orders['bids'], key=flt_fun, reverse=True)[0]
            except IndexError:
                bb = None
            try:
                ba = sorted(cur_orders['asks'], key=flt_fun)[0]
            except IndexError:
                ba = None
            self.debug("ba {} | bb {}".format(str(bb), str(ba)))

            if self.get_inventory() >= 0:
                #if ivnentory is positive, we only concern ourselves with maybe removing some ask
                try:
                    self.debug("ba price {} | bbo {} | equal {}".format(
                        ba['price'], red(self.bbo(lvl=5)['ask'][0]),
                        ba['price'] == red(self.bbo(lvl=5)['ask'][0])))
                except Exception as e:
                    self.debug(
                        "debugger error {} , probable cause BBO @ {}".format(
                            e, self.bbo(lvl=5)))
                if ba['price'] == red(self.bbo(lvl=5)['ask'][0]):
                    #print("in flicker ask remove")
                    self.debug("ba t mkt {} | ba q pos {}".format(
                        ba['t_market'] > self.grace_time_q,
                        ba['q_pos'] > self.q_ratio_threshold))
                    print('last bbo'.format(self.last_bbo))

                    if ba['q_pos'] and ba['t_market'] and\
                                    ba['q_pos'] > self.q_ratio_threshold \
                                    and ba['t_market'] > self.grace_time_q:
                        self.debug("removing inside ask (and burning value)")
                        ask_post_pxs.pop(0)
                        if not self.last_bbo:
                            self.last_bbo = dict()
                        if not self.last_bbo.get('ask'):
                            self.last_bbo['ask'] = dered(
                                self.bbo(lvl=5)['ask'][0])

                if self.last_bbo and self.last_bbo.get('ask'):
                    self.debug("We had a burned ask value")
                    ask_post_pxs.pop(0)

            if self.get_inventory() <= 0:
                #if ivnentory is negative, we only concern ourselves with maybe removing some bid
                try:
                    self.debug("bb price {} | bbo {} | equal {}".format(
                        bb['price'], red(self.bbo(lvl=5)['bid'][0]),
                        bb['price'] == red(self.bbo(lvl=5)['bid'][0])))
                except Exception as e:
                    self.debug(
                        "debugger error {} , probable cause BBO @ {}".format(
                            e, self.bbo(lvl=5)))
                if bb['price'] == red(self.bbo(lvl=5)['bid'][0]):
                    #print("in flicker bid remove")
                    self.debug("bb t mkt {} | bb q pos {}".format(
                        bb['t_market'] > self.grace_time_q,
                        bb['q_pos'] > self.q_ratio_threshold))

                    if bb['q_pos'] and bb['t_market'] and\
                                    bb['q_pos'] > self.q_ratio_threshold \
                                    and bb['t_market'] > self.grace_time_q:
                        self.debug("removing inside bid (and burning value)")
                        bid_post_pxs.pop(0)
                        if not self.last_bbo:
                            self.last_bbo = dict()
                        if not self.last_bbo.get('bid'):
                            self.last_bbo['bid'] = dered(
                                self.bbo(lvl=5)['bid'][0])

                if self.last_bbo and self.last_bbo.get('bid'):
                    self.debug("We had a burned bid value")
                    bid_post_pxs.pop(0)

        return bid_post_pxs, ask_post_pxs
Пример #26
0
    async def show(self, ctx, pos):
        """View the details of an item in your inventory by position number or equipped gear by slot name (obtained using the 'inv' command)."""
        character = self.get(ctx.author)

        if pos.isdigit() and int(pos) + 1 <= len(character.inventory):
            it = character.inventory[int(pos)]
        elif isinstance(pos, str) and pos in weapon.valid_slots:
            it = getattr(character, 'eq_' + pos)
        else:
            await ctx.author.send(
                utilities.red('Invalid inventory position or gear slot.'))
            return

        if it is not None:
            item_string = '''
====================ITEM===================='''
            item_string += f'''
{it.name} - Level {it.level} {utilities.get_rarity_symbol(it.rarity)}

"{it.description}"
'''
            if it.itype == ItemType.weapon.value:
                item_string += f'''
Class: {WeaponType(it.weapon_type).name.capitalize()}
Damage: {weapon.get_damages_display_string(it)}
Crit Damage: +{it.crit_damage}

Requirements
------------
{utilities.get_requirements_display_string(it)}

Bonuses
-------
{weapon.get_bonuses_display_string(it)}

Sockets
-------
{utilities.get_socket_display(it)}
'''
            elif it.itype == ItemType.potion.value:
                item_string += f'''
Effects
-------
{utilities.get_consumable_effects_display_string(it)}
'''
            elif it.itype in [
                    ItemType.head.value, ItemType.chest.value,
                    ItemType.belt.value, ItemType.boots.value,
                    ItemType.gloves.value, ItemType.amulet.value,
                    ItemType.ring.value
            ]:
                item_string += f'''
Class: {ItemType(it.itype).name.capitalize()}

Requirements
------------
{utilities.get_requirements_display_string(it)}

Bonuses
-------
{armor.get_bonuses_display_string(it)}

Sockets
-------
{utilities.get_socket_display(it)}
'''
            item_string += f'''
Weight: {it.weight}
Value: {it.value}'''
            await ctx.author.send(item_string)
        else:
            await ctx.author.send('No item equipped in that slot.')