0

I'm trying to write a function that updates its local variable each time it is run but it is not working for some reason.

def max_equity(max_equity=0):
    
    if current_equity() > max_equity:
        max_equity = current_equity()
        print(max_equity)
        return max_equity
    
    else:
        print(max_equity)
        return max_equity

and the function which it is calling

def current_equity():
    for n in range(len(trade_ID_tracker)-1):
        
        equity_container = 0
                
        if (trade_ID_tracker[n,2]) == 0:
                    
            break
                    
        else:

            if (trade_ID_tracker[n, 1].astype(int) == long):
                equity_container += (df.loc[tbar_count,'Ask_Price'] - trade_ID_tracker[n, 2]) * trade_lots * pip_value * 1000 

            elif (trade_ID_tracker[n, 1].astype(int) == short):
                equity_container += 0 - (df.loc[tbar_count,'Ask_Price'] - trade_ID_tracker[n, 2]) * trade_lots * pip_value * 10000

    return (current_balance + equity_container)

but for some reason the max_equity() function prints current_equity() which I can only imagine means that either:

if current_equity() > max_equity:

is not doing it's job and is triggering falsely

or

max_equity = current_equity()

is not doing its job and max_equity starts at zero every time it is run.

In other words if I put max_equity() in a loop where current_equity() is

[1,2,3,4,5,4,3,2,1]

then max_equity() should return

[1,2,3,4,5,5,5,5,5]

But instead it returns

[1,2,3,4,5,4,3,2,1]

Here's a quick example test

ar = [1,2,3,4,5,4,3,2,1]


def stuff(max_equity=0):
    if ar[n] > max_equity:
        max_equity = ar[n]
        print(max_equity)
    
    else:
         print(max_equity)
            

for n in range(len(ar)):
    stuff()
    
    

Either way I'm kind of stumped. Any advice?

coinmaster
  • 133
  • 6
  • 1
    For debugging help, you need to provide a [mre] including complete code (i.e. the call to `max_equity()`, input, expected output, and actual output. – wjandrea Aug 25 '21 at 17:08
  • The code given doesn't look complete enough to dump into a sandbox and run, even as-extended. Part of the point of asking for a MRE is so others can reproduce the problem themselves _and test proposed answers in practice_. For example, the code refers to a `trade_ID_tracker` that's never defined, so it can't be run -- meaning answers can't be tested. – Charles Duffy Aug 25 '21 at 17:16
  • 1
    ...trying to run the code in your question in a sandbox (repl.it, ideone.com, etc) is a good way to try to ensure that it's self-contained. – Charles Duffy Aug 25 '21 at 17:18
  • 1
    Very bad idea to have a variable name `max_equity` identical to the enclosing function name. Also be aware of [mutable default arguments](https://docs.python-guide.org/writing/gotchas/) (doesn't affect you in the current code with `max_equity=0`, but be aware of the behavior with mutable arguments like `[]`). – jarmod Aug 25 '21 at 17:18
  • 1
    That said, for max_equity to start at 0 on every call is completely correct and normal behavior, because integers _aren't_ mutable (it smells to me like you're expecting or counting on the behavior that @jarmod's link points to, but that behavior doesn't happen for non-mutable types). – Charles Duffy Aug 25 '21 at 17:18
  • "is not doing its job and max_equity starts at zero every time it is run." **because you set it to zero as a default argument, and call it with the default argument every time**. Why do you *expect* it ever to be not zero? – juanpa.arrivillaga Aug 25 '21 at 17:39
  • I don't know, I thought default meant that it is the starting value for the variable. How do I define the variable "max_equity" without resetting to the variable definition on every call? – coinmaster Aug 25 '21 at 17:43
  • 1
    This is a duplicate of https://stackoverflow.com/questions/26630821/static-variable-in-python. There are some good options in the accepted answer and the other answers. – Matthias Fripp Aug 25 '21 at 17:52

1 Answers1

1

local function variables are reset at each function call. This is essential for the behavior of functions as idempotent, and is a major factor in the success of the procedural programming approach: a function can be called form multiple contexts, and even in parallel, in concurrent threads, and it will yield the same result.

A big exception, and most often regarded as one of the bigger beginner traps of Python is that, as parameters are reset to the default values specified in the function definition for each call, if these values are mutable objects, each new call will see the same object, as it has been modified by previous calls.

This means it could be done on purpose by, instead of setting your default value as 0 you would set it as a list which first element was a 0. At each run, you could update that value, and this change would be visible in subsequent calls.

This approach would work, but it is not "nice" to depend on a side-effect of the language in this way. The official (and nice) way to keep state across multiple calls in Python is to use objects rather than functions.

Objects can have attributes tied to them, which are both visible and writable by its methods - which otherwise have their own local variables which are re-started at each call:

class MaxEquity:
    def __init__(self):
        self.value = 0

    def update(max_equity=0):
        current = current_equity()
        if current > self.value:
            self.value = current
        return self.value
            
# the remainder of the code should simply create a single instance 
# of that like ]
max_equity = MaxEquity()

# and eeach time yoiu want the max value, you should call its "update"
# method
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • I'm trying to avoid updating global variables which I'm told is bad practice. Is there a way to update a variable within a function or is that not how it's done? Sorry for dumb question. – coinmaster Aug 25 '21 at 17:50
  • @coinmaster *you are updating a variable within a function*. What this answer is explaining to you is that *local variables cease to exist after the function terminates* (not necessarily the objects they are referring to, of course). – juanpa.arrivillaga Aug 25 '21 at 17:53
  • I tried the above method by calling max_equity.update and then using print(max_equity.value) and print(max_equity.update) and print(max_equity.value) returns 0 every time it is run and print(max_equity.update) returns a memory location. How do I get this to work as you stated? – coinmaster Aug 25 '21 at 19:36
  • you have to call the update method, not print it: `max_equity.update()`, just like you called the former function. (value, on the other hand, is a property - using `print(max_equity.value)` is ok) – jsbueno Aug 26 '21 at 14:27