Calculate quote volumes (for a financial instrument) within numeric constraints The function below is part of a trading system. Its purpose is to assign a volume (order size) to a bid (buy) quote and and ask (sell) quote, depending on the value of the position_size argument. 

This trading system strictly cannot exceed a position limit of 100 in either direction, so our order volumes need to never exceed 100 when combined with the absolute value of current position.

However there is one caveat. Occasionally, for uncontrollable external reasons, a bid or ask (buy or sell order) will be executed twice before its price can be re-adjusted. 

So any bid_volume or ask_volume returned by this function needs to be at most, half the value of 100 - position_size, in order to account for the occasional double execution. 

Thats why at any step of the if-else blocks below, doubling the ask_volume or bid_volume plus current_position will not exceed 100.

What is the fastest way to achieve this with Python, other than the below code?

def adjust_volume(position_size):

    # Long.
    if position_size &gt; 0:

        if position_size &lt; 45:
            bid_volume = 45 - position_size
            ask_volume = 50

        elif position_size &gt;= 45 and position_size &lt; 65:
            bid_volume = 65 - position_size
            ask_volume = 50

        elif position_size &gt;= 65 and position_size &lt; 82:
            bid_volume = 82 - position_size
            ask_volume = 50

        elif position_size &gt;= 82 and position_size &lt; 100:
            bid_volume = 91 - position_size
            ask_volume = 85

    # Short.
    elif position_size &lt; 0:

        abs_position_size = abs(position_size)

        if position_size &gt; -45:
            bid_volume = 10
            ask_volume = 45 - abs_position_size

        elif position_size &lt;= -45 and position_size &gt; -65:
            bid_volume = 50
            ask_volume = 65 - abs_position_size

        elif position_size &lt;= -65 and position_size &gt; -82:
            bid_volume = 50
            ask_volume = 82 - abs_position_size

        elif position_size &lt;= -82 and position_size &gt; -100:
            bid_volume = 75
            ask_volume = 85 - abs_position_size

        elif position_size == 0:

            bid_volume = 30
            ask_volume = 30

    return position_size, bid_volume, ask_volume


position_size, bid_volume, ask_volume = adjust_volume(-76)

print("bid_volume:", bid_volume)
print("ask_volume:", ask_volume)
Bug

adjust_volume(0) presently results in:


  UnboundLocalError: local variable 'bid_volume' referenced before assignment


since if position_size == 0: is currently indented inside the elif position_size &lt; 0: statement, so is unreachable.  (This could be a result of poor formatting when copying the code into the question post.)

Possible Bug

Some volume calculations result in negative volumes.  (adjust_volume(99) gives bid_volume == -8, and adjust_volume(-99) gives ask_volume == -14, which seem like invalid results.)

Possible Bug

If adjust_volume() is given an argument >= 100 or &lt;= -100, it also fails with an UnboundLocalError.  Limits should be checked and a ValueError be raised instead.


  This trading system strictly cannot exceed a position limit of 100 in either direction, so our order volumes need to never exceed 100 when combined with the absolute value of current position.


100 does not exceed 100, so it is likely the original implementation should have allowed +100 and -100 as well.  But these currently result in UnboundLocalError.

Chained comparisons

I have to say, this condition makes my brain hurt:

    elif position_size &lt;= -65 and position_size &gt; -82:


It took me several moments to unwind what the range was, and I had to triple check that I got it right.  It would be much clearer to express as:

    elif -82 &lt; position_size and position_size &lt;= -65:


or using the chaining comparison operations:

    elif -82 &lt; position_size &lt;= -65:


Bisect

You have 9 ranges:


-100 &lt; position_size &lt;= -82
-82 &lt; position_size &lt;= -65
-65 &lt; position_size &lt;= -45
-45 &lt; position_size &lt; 0
0 &lt;= position_size &lt;= 0
0 &lt; position_size &lt; 45
45 &lt;= position_size &lt; 65
65 &lt;= position_size &lt; 82
82 &lt;= position_size &lt; 100


Instead of using a tree of if-elif-else statements to locate the correct range, you could bisect the list -81, -64, -44, 0, 1, 45, 65, 82 to determine the correct range bucket.

Note: Negative bucket limits have been increased by 1 to account for the difference in whether the lower limit or the upper limit is included as position_size goes from negative values to positive values.

from bisect import bisect

POSITION = (-81, -64, -44, 0, 1, 45, 65, 82,)
BID_ASK = (
    (75, 85), # -100 &lt; pos &lt;= -82
    (50, 82), # -82 &lt; pos &lt;= -65
    (50, 65), # -65 &lt; pos &lt;= -45
    (10, 45), # -45 &lt; pos &lt; 0
    (30, 30), # 0 &lt;= pos &lt;= 0
    (45, 50), # 0 &lt; pos &lt; 45
    (65, 50), # 45 &lt;= pos &lt; 65
    (82, 50), # 65 &lt;= pos &lt; 82
    (91, 85), # 82 &lt;= pos &lt; 100
)

def adjust_volume(position_size):

    if not(-100 &lt; position_size &lt; 100):
        raise ValueError("position size out of range")

    bucket = bisect(POSITION, position_size)

    bid_volume, ask_volume = BID_ASK[bucket]
    if position &gt;= 0:
        bid_volume -= position_size
    else:
        ask_volume -= abs(position_size)

    return position_size, bid_volume, ask_volume