0

Trying to program an API trading algorithm- I need to check whether an order has been filled, and if it has been filled, place the new order, and if the order has not been filled or there is no order, do nothing (return). The variable that holds 'Filled' or 'Not filled' is only declared if there is an open order. I want it to basically send the order if the variable is 'Filled', and ALSO send the order if the variable is undefined, but NOT send the order if it is unfilled and undefined (no orders ever sent, ie. initial run through)...

The original problem is that it sends a second order even if the previous order is not filled yet, so I created a variable in the 'openOrders' function that shows the status of the order. But if there are no orders, the variable is undefined. So I want it to send the order if it is undefined (no orders), and send the order if the variable is 'filled'.

I had this code but the first line throws it off because it doesn't recognize none as undefined. Any suggestions?

if self.openOrderStatus == None:  #<--                           
      # SELL

elif self.openOrderStatus != 'Filled':
      return
else:
      # SELL
Heinrich
  • 340
  • 1
  • 4
  • 12
  • 3
    You should not write code where a variable may or may not be defined depending on some condition. This is an [XY problem](https://xyproblem.info/). – kaya3 Mar 23 '21 at 21:45
  • 1
    No you can't. However I disagree with @kaya3, the "pythonic" way to handle this would be to put the `if` inside a `try`/`except` and handle any `NameError` exception gracefully. Another (non-pythonic) way would be to use `getattr()` to check to see of it exists before trying to access it. – martineau Mar 23 '21 at 21:47
  • 2
    The most obvious solution here is to initialize `self.openOrderStatus` to `None` when you create the instance that contains it. Is there some reason that you can't do that? – CryptoFool Mar 23 '21 at 21:48
  • 1
    ...that is to say, if you make your `__init__(self):` contain `self.openOrderStatus = None`, the exception becomes impossible. – Charles Duffy Mar 23 '21 at 21:52
  • I think this is a very opinion based answer. Some prefer to have clean code and others tend to use try except to address any penalty. I would go with initialization before using – Joe Ferndz Mar 23 '21 at 21:57
  • 2
    Handling a `NameError` for normal control flow is, I'm sorry, not a sensible thing to do. If you do this then your program is going to do strange and unexpected things if you make a typo, instead of giving you a useful error message. A `NameError` should mean that your program is written incorrectly. – kaya3 Mar 23 '21 at 21:57
  • `hasattr(self,'openOrderStatus')` determines if attribute `openOrderStatus` is an attribute of the object. – jpf Mar 23 '21 at 21:58
  • 1
    @JoeFerndz, ...however, there are pretty clear efficiency arguments here, so it's not just style/opinion. Handling exceptions is expensive. Having known types also lets you use classes with slots, which improves memory efficiency. – Charles Duffy Mar 23 '21 at 21:58
  • For more information on handling errors in Python see [my answer](https://stackoverflow.com/a/3931746/355230) to another question. – martineau Mar 23 '21 at 21:58
  • 1
    @Joe Ferndz: The question is whether undefined variables can be referenced — and the answer isn't based on opinion. What to do about it or how to avoid it are another matter, but not the topic of the question. – martineau Mar 23 '21 at 22:00
  • @CharlesDuffy, agree. handling exceptions helps. I would argue about having try except for things where we may be able to address it easier. Otherwise we end up with too many try excepts. I did upvote your comment as there are definitely efficiencies. – Joe Ferndz Mar 23 '21 at 22:01

2 Answers2

1

Just give openOrderStatus an initial value of None when you create the containing object. That represents a non-existent order. Then the code you show us will work as is. For example:

class SomeClass:

    def __init__(self):
        self.openOrderStatus = None
        ...

    def some_method(self):

        if self.openOrderStatus == None:  # <-- no throw now
            # SELL
            ...
        elif self.openOrderStatus != 'Filled':
            return
        else:
            # SELL
            ...
CryptoFool
  • 21,719
  • 5
  • 26
  • 44
0

If you want to coerce attributes that don't exist to None, an easy way to do that is with getattr() with the default value filled in:

if getattr(self, 'openOrderStatus', None) == None:  #<--                           
      pass # SELL
elif getattr(self, 'openOrderStatus', None) != 'Filled':
      return
else:
      pass # SELL

However, it would be much better practice to initialize your objects such that every attribute you want always has a value, even if that value is None.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441