# Relative Strength Index algorithm for stock values

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_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,
sell=False)
elif rsi1 >= 70:
cash_balance, stocks_owned = transact(cash_balance,
stocks_owned,
stocks_per,
sell=True)
else:
pass
except ValueError:
pass
try:
if rsi2 <= 30:
cash_balance, stocks_owned = transact(cash_balance,
stocks_owned,
stocks_per,
sell=False)
elif rsi2 >= 70:
cash_balance, stocks_owned = transact(cash_balance,
stocks_owned,
stocks_per,
sell=True)
else:
pass
except ValueError:
pass
day = day + 1
if price1 > price2:
cash_balance, stocks_owned = transact(cash_balance,
stocks_owned,
stocks_owned,
sell=True)
else:
cash_balance, stocks_owned = transact(cash_balance,
stocks_owned,
stocks_owned,
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.

• The indentation looked wrong - I believe I've corrected it, but do please check that I got it right! May 11 at 15:48

• 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:
if rsi >= 70:
sell = True

cash_balance, stocks_owned = transact(cash_balance,
stocks_owned,
stocks_per,
price,

• 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.

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