0
\$\begingroup\$

This is an Relative Strength Index algorithm able to buy and sell stock based on values from basic stock CSVs. It works correctly and well, but I'm not sure if it can be better optimized as it basically repeats itself twice to operate on the two stock values it's given. I can only use python itself, no numpy or anything.

def alg_rsi(filename_1, filename_2):
    lookback = 21
    cash_balance = 10000
    stocks_owned = 0
    column_choice = 4
    day = 1
    file1 = open(filename_1).readlines()
    file2 = open(filename_2).readlines()
    file1_length = sum(1 for line in file1)
    file2_length = sum(1 for line in file2)
    if file1_length >= file2_length:
        length = file2_length
    else:
        length = file1_length
    for i in range(length - lookback - 1):
        tday = day + lookback
        gains = []
        losses = []
        for i in range(lookback):
            today = float(file1[tday][:-1].split(',')[column_choice])
            yesterday = float(file1[tday - 1][:-1].split(',')[column_choice])
            if today > yesterday:
                gain = today - yesterday
                gains.append(gain)
            else:
                loss = yesterday - today
                losses.append(loss)
            tday = tday - 1
        totalgain1 = sum(gains)
        totalloss1 = sum(losses)
        averagegain1 = totalgain1 / lookback
        averageloss1 = totalloss1 / lookback
        rsi1 = 100 - (100 / (1 + (averagegain1 / averageloss1)))
        gains.clear()
        losses.clear()
        tday = day + lookback
        for i in range(lookback):
            today = float(file2[tday][:-1].split(',')[column_choice])
            yesterday = float(file2[tday - 1][:-1].split(',')[column_choice])
            if today > yesterday:
                gain = today - yesterday
                gains.append(gain)
            else:
                loss = yesterday - today
                losses.append(loss)
            tday = tday - 1
        totalgain2 = sum(gains)
        totalloss2 = sum(losses)
        averagegain2 = totalgain2 / lookback
        averageloss2 = totalloss2 / lookback
        rsi2 = 100 - (100 / (1 + (averagegain2 / averageloss2)))
        gains.clear()
        losses.clear()
        stocks_per = 10
        price1 = float(file1[day + lookback][:-1].split(',')[column_choice])
        price2 = float(file2[day + lookback][:-1].split(',')[column_choice])
        try:
            if rsi1 <= 30:
                cash_balance, stocks_owned = transact(cash_balance,
                                                      stocks_owned,
                                                      stocks_per,
                                                      price1, buy=True,
                                                      sell=False)
            elif rsi1 >= 70:
                cash_balance, stocks_owned = transact(cash_balance,
                                                      stocks_owned,
                                                      stocks_per,
                                                      price1, buy=False,
                                                      sell=True)
            else:
                pass
        except ValueError:
            pass
        try:
            if rsi2 <= 30:
                cash_balance, stocks_owned = transact(cash_balance,
                                                      stocks_owned,
                                                      stocks_per,
                                                      price2, buy=True,
                                                      sell=False)
            elif rsi2 >= 70:
                cash_balance, stocks_owned = transact(cash_balance,
                                                      stocks_owned,
                                                      stocks_per,
                                                      price2, buy=False,
                                                      sell=True)
            else:
                pass
        except ValueError:
            pass
        day = day + 1
    if price1 > price2:
        cash_balance, stocks_owned = transact(cash_balance,
                                              stocks_owned,
                                              stocks_owned,
                                              price1, buy=False,
                                              sell=True)
    else:
        cash_balance, stocks_owned = transact(cash_balance,
                                              stocks_owned,
                                              stocks_owned,
                                              price2, buy=False,
                                              sell=True)
    return stocks_owned, cash_balance

Overall I'm not super pressed if this is how it has to be, as it still works quickly; it just seems to me like there's too many redundant parts.

\$\endgroup\$
1
  • \$\begingroup\$ The indentation looked wrong - I believe I've corrected it, but do please check that I got it right! \$\endgroup\$ May 11 at 15:48
1
\$\begingroup\$
  • Computation of rsi1 (and rsi2) are a bit more complicated as necessary. Gains and losses are accumulated in their respective lists, only to be summed later on. Get rid of the lists:

          if today > yesterday:
              gain += today - yesterday
          else:
              loss += yesterday - today
    

    Computing averages is also redundant.

          averagegain1 = totalgain1 / lookback
          averageloss1 = totalloss1 / lookback
          rsi1 = 100 - (100 / (1 + (averagegain1 / averageloss1)))
    

    is a very long way to say

          rsi1 = 100 - (100 / (1 + (totalgain1 / totalloss1)))
    

    Math guarantees that the result will be the same. lookback just cancels.

    Also you have to be very careful with division by totalloss. It is quite possible that it is zero. BTW, I would simplify the formula to 100 * gain/(gain + loss).

  • You didn't show transact. From what I see, passing both buy and sell seems redundant. They are always opposite to each other.

    If setting them both to False results in no transaction, consider

      buy, sell = False, False
      if rsi <= 30:
          buy = True
      if rsi >= 70:
          sell = True
    
      cash_balance, stocks_owned = transact(cash_balance,
                                            stocks_owned,
                                            stocks_per,
                                            price,
                                            buy, sell)
    
  • You may achieve a certain performance increase by not recomputing gains and losses over the entire lookback period. Using a sliding window.

  • As noted in another answer, factor the repeated code into a function.

\$\endgroup\$
0
\$\begingroup\$
if file1_length >= file2_length:
    length = file2_length
else:
    length = file1_length

Or more succinctly as length = max(file1_length, file2_length)


tday

What is tday? It does not look like typo for today


for i in range(lookback):
    today = float(file1[tday][:-1].split(',')[column_choice])
    yesterday = float(file1[tday - 1][:-1].split(',')[column_choice])
    if today > yesterday:
        gain = today - yesterday
        gains.append(gain)
    else:
        loss = yesterday - today
        losses.append(loss)
    tday = tday - 1
totalgain1 = sum(gains)
totalloss1 = sum(losses)
averagegain1 = totalgain1 / lookback
averageloss1 = totalloss1 / lookback

This whole chunk is duplicated. I suggest making a function to remove duplicate code

There are more duplicated chunks, and it looks like an array of size 2 would be useful

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.