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.
-
\$\begingroup\$ The indentation looked wrong - I believe I've corrected it, but do please check that I got it right! \$\endgroup\$Toby Speight– Toby Speight2021年05月11日 15:48:22 +00:00Commented May 11, 2021 at 15:48
2 Answers 2
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
Computation of
rsi1
(andrsi2
) 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 to100 * gain/(gain + loss)
.You didn't show
transact
. From what I see, passing bothbuy
andsell
seems redundant. They are always opposite to each other.If setting them both to
False
results in no transaction, considerbuy, 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.