Calculate quote volumes (for a financial instrument) within numeric constraints
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