251 lines
11 KiB
Python
Executable File
251 lines
11 KiB
Python
Executable File
import pandas as pd
|
|
from datetime import datetime
|
|
from ta.utils import *
|
|
from ta.volatility import *
|
|
from ta.momentum import *
|
|
from ta.trend import *
|
|
from ta.volume import *
|
|
|
|
|
|
|
|
class rating_model:
|
|
def __init__(self, df):
|
|
#Results are in the form of
|
|
# Strong Sell => 0
|
|
# Sell => 1
|
|
# Neutral => 2
|
|
# Buy => 3
|
|
# Strong Buy => 4
|
|
|
|
self.data = df
|
|
|
|
def compute_overall_signal(self, data):
|
|
ratingMap = {
|
|
'Strong Sell': 0,
|
|
'Sell': 1,
|
|
'Neutral': 2,
|
|
'Buy': 3,
|
|
'Strong Buy': 4
|
|
}
|
|
|
|
# Extract overall ratings from the data
|
|
overallRating = {item['name']: item['signal'] for item in data}
|
|
|
|
# Compute mean overall rating
|
|
mean_overall_rating = sum(ratingMap[val] for val in overallRating.values()) / len(overallRating)
|
|
mean_overall_rating /= 4.0
|
|
|
|
# Determine overall signal based on mean rating
|
|
if 0 < mean_overall_rating <= 0.15:
|
|
overall_signal = "Strong Sell"
|
|
elif 0.15 < mean_overall_rating <= 0.45:
|
|
overall_signal = "Sell"
|
|
elif 0.45 < mean_overall_rating <= 0.55:
|
|
overall_signal = 'Neutral'
|
|
elif 0.55 < mean_overall_rating <= 0.8:
|
|
overall_signal = 'Buy'
|
|
elif 0.8 < mean_overall_rating <= 1.0:
|
|
overall_signal = "Strong Buy"
|
|
else:
|
|
overall_signal = 'n/a'
|
|
|
|
return overall_signal
|
|
|
|
def ta_rating(self):
|
|
df = pd.DataFrame()
|
|
df['sma_20'] = sma_indicator(self.data['close'], window=20)
|
|
df['sma_50'] = sma_indicator(self.data['close'], window=50)
|
|
df['ema_20'] = ema_indicator(self.data['close'], window=20)
|
|
df['ema_50'] = ema_indicator(self.data['close'], window=50)
|
|
df['wma'] = wma_indicator(self.data['close'], window=20)
|
|
df['adx'] = adx(self.data['high'],self.data['low'],self.data['close'])
|
|
df["adx_pos"] = adx_pos(self.data['high'],self.data['low'],self.data['close'])
|
|
df["adx_neg"] = adx_neg(self.data['high'],self.data['low'],self.data['close'])
|
|
df['williams'] = WilliamsRIndicator(high=self.data['high'], low=self.data['low'], close=self.data['close']).williams_r()
|
|
|
|
# Assign ratings based on SMA values
|
|
df['sma_rating'] = 'Neutral'
|
|
if self.data['close'].iloc[-1] < df['sma_50'].iloc[-1] and df['sma_20'].iloc[-1] < df['sma_50'].iloc[-1]:
|
|
df['sma_rating'] = 'Strong Sell'
|
|
elif self.data['close'].iloc[-1] < df['sma_20'].iloc[-1] and df['sma_20'].iloc[-1] < df['sma_50'].iloc[-1]:
|
|
df['sma_rating'] = 'Sell'
|
|
elif df['sma_20'].iloc[-1] <= self.data['close'].iloc[-1] <= df['sma_50'].iloc[-1]:
|
|
df['sma_rating'] = 'Neutral'
|
|
elif self.data['close'].iloc[-1] > df['sma_20'].iloc[-1] and df['sma_20'].iloc[-1] > df['sma_50'].iloc[-1]:
|
|
df['sma_rating'] = 'Buy'
|
|
elif self.data['close'].iloc[-1] > df['sma_50'].iloc[-1] and df['sma_20'].iloc[-1] > df['sma_50'].iloc[-1]:
|
|
df['sma_rating'] = 'Strong Buy'
|
|
|
|
# Assign ratings for ema
|
|
df['ema_rating'] = 'Neutral'
|
|
|
|
if self.data['close'].iloc[-1] < df['ema_50'].iloc[-1] and df['ema_20'].iloc[-1] < df['ema_50'].iloc[-1]:
|
|
df['ema_rating'] = 'Strong Sell'
|
|
elif self.data['close'].iloc[-1] < df['ema_20'].iloc[-1] and df['ema_20'].iloc[-1] < df['ema_50'].iloc[-1]:
|
|
df['ema_rating'] = 'Sell'
|
|
elif df['ema_20'].iloc[-1] <= self.data['close'].iloc[-1] <= df['ema_50'].iloc[-1]:
|
|
df['ema_rating'] = 'Neutral'
|
|
elif self.data['close'].iloc[-1] > df['ema_20'].iloc[-1] and df['ema_20'].iloc[-1] > df['ema_50'].iloc[-1]:
|
|
df['ema_rating'] = 'Buy'
|
|
elif self.data['close'].iloc[-1] > df['ema_50'].iloc[-1] and df['ema_20'].iloc[-1] > df['ema_50'].iloc[-1]:
|
|
df['ema_rating'] = 'Strong Buy'
|
|
|
|
# Assign ratings based on wma
|
|
df['wma_rating'] = pd.cut(self.data['close'] - df['wma'],
|
|
bins=[float('-inf'), -10, -5, 0, 5, 10],
|
|
labels=['Strong Sell', 'Sell', 'Neutral', 'Buy', 'Strong Buy'])
|
|
|
|
# Assign ratings based on adx
|
|
if df['adx'].iloc[-1] > 50 and df['adx_neg'].iloc[-1] > df['adx_pos'].iloc[-1]:
|
|
df['adx_rating'] = 'Strong Sell'
|
|
elif df['adx'].iloc[-1] >=25 and df['adx'].iloc[-1] <=50 and df['adx_neg'].iloc[1] > df['adx_pos'].iloc[-1]:
|
|
df['adx_rating'] = 'Sell'
|
|
elif df['adx'].iloc[-1] < 25:
|
|
df['adx_rating'] = 'Neutral'
|
|
elif df['adx'].iloc[-1] >=25 and df['adx'].iloc[-1] <=50 and df['adx_pos'].iloc[-1] > df['adx_neg'].iloc[-1]:
|
|
df['adx_rating'] = 'Buy'
|
|
elif df['adx'].iloc[-1] > 50 and df['adx_pos'].iloc[-1] > df['adx_neg'].iloc[-1]:
|
|
df['adx_rating'] = 'Strong Buy'
|
|
else:
|
|
df['adx_rating'] = 'Neutral'
|
|
|
|
|
|
# Assign ratings based on williams
|
|
df['williams_rating'] = 'Neutral'
|
|
df.loc[df["williams"] < -80, 'williams_rating'] = "Strong Sell"
|
|
df.loc[(df["williams"] >= -80) & (df["williams"] < -50), 'williams_rating'] = "Sell"
|
|
df.loc[(df["williams"] >= -50) & (df["williams"] <= -20), 'williams_rating'] = "Buy"
|
|
df.loc[df["williams"] > -20, 'williams_rating'] = "Strong Buy"
|
|
|
|
#=========Momentum Indicators ============#
|
|
|
|
|
|
aroon = AroonIndicator(self.data['close'], low=self.data['low'], window=14)
|
|
df['rsi'] = rsi(self.data['close'], window=14)
|
|
df['stoch_rsi'] = stochrsi_k(self.data['close'], window=14, smooth1 = 3, smooth2 =3)*100
|
|
|
|
df['macd'] = macd(self.data['close'])
|
|
df['macd_signal'] = macd_signal(self.data['close'])
|
|
df['macd_hist'] = 2*macd_diff(self.data['close'])
|
|
df['roc'] = roc(self.data['close'], window=14)
|
|
df['cci'] = CCIIndicator(high=self.data['high'], low=self.data['low'], close=self.data['close']).cci()
|
|
df['mfi'] = MFIIndicator(high=self.data['high'], low=self.data['low'], close=self.data['close'], volume=self.data['volume']).money_flow_index()
|
|
|
|
# Assign ratings based on MFI values
|
|
df['mfi_rating'] = pd.cut(df['mfi'],
|
|
bins=[-1, 20, 40, 60, 80, 101],
|
|
labels=['Strong Buy', 'Buy', 'Neutral', 'Sell', 'Strong Sell'])
|
|
|
|
# Assign ratings based on RSI values
|
|
df['rsi_rating'] = pd.cut(df['rsi'],
|
|
bins=[-1, 30, 50, 60, 70, 101],
|
|
labels=['Strong Buy', 'Buy', 'Neutral', 'Sell', 'Strong Sell'])
|
|
|
|
# Assign ratings based on Stoch RSI values
|
|
df['stoch_rsi_rating'] = pd.cut(df['stoch_rsi'],
|
|
bins=[-1, 30, 50, 60, 70, 101],
|
|
labels=['Strong Buy', 'Buy', 'Neutral', 'Sell', 'Strong Sell'])
|
|
|
|
|
|
# Assign ratings for macd
|
|
if df['macd'].iloc[-1] < df['macd_signal'].iloc[-1] and df['macd_hist'].iloc[-1] < 0 \
|
|
and df['macd_hist'].iloc[-1] > df['macd_hist'].iloc[-2]:
|
|
df['macd_rating'] = 'Strong Sell'
|
|
elif df['macd'].iloc[-1] < df['macd_signal'].iloc[-1] and df['macd_hist'].iloc[-1] < 0 \
|
|
and df['macd_hist'].iloc[-1] < df['macd_hist'].iloc[-2]:
|
|
df['macd_rating'] = 'Sell'
|
|
elif abs(df['macd'].iloc[-1] - df['macd_signal'].iloc[-1]) < 0.01 and abs(df['macd_hist'].iloc[-1]) < 0.01:
|
|
df['macd_rating'] = 'Neutral'
|
|
elif df['macd'].iloc[-1] > df['macd_signal'].iloc[-1] and df['macd_hist'].iloc[-1] > 0 and df['macd_hist'].iloc[-1] < df['macd_hist'].iloc[-2]:
|
|
df['macd_rating'] = 'Buy'
|
|
elif df['macd'].iloc[-1] > df['macd_signal'].iloc[-1] and df['macd_hist'].iloc[-1] > 0 and df['macd_hist'].iloc[-1] > df['macd_hist'].iloc[-2]:
|
|
df['macd_rating'] = 'Strong Buy'
|
|
else:
|
|
df['macd_rating'] = 'Neutral'
|
|
|
|
|
|
# Assign ratings for roc
|
|
if df['roc'].iloc[-1] < -10:
|
|
df['roc_rating'] = 'Strong Sell'
|
|
elif df['roc'].iloc[-1] > -10 and df['roc'].iloc[-1] <= -5:
|
|
df['roc_rating'] = 'Sell'
|
|
elif df['roc'].iloc[-1] > -5 and df['roc'].iloc[-1] < 5:
|
|
df['roc_rating'] = 'Neutral'
|
|
elif df['roc'].iloc[-1] >=5 and df['roc'].iloc[-1] < 10:
|
|
df['roc_rating'] = 'Buy'
|
|
elif df['roc'].iloc[-1] >= 10:
|
|
df['roc_rating'] = 'Strong Buy'
|
|
else:
|
|
df['roc_rating'] = 'Neutral'
|
|
|
|
|
|
|
|
# Define CCI threshold values for signals
|
|
cci_strong_sell_threshold = -100
|
|
cci_sell_threshold = -50
|
|
cci_buy_threshold = 50
|
|
cci_strong_buy_threshold = 100
|
|
|
|
# Assign signals based on CCI values
|
|
if df['cci'].iloc[-1] < cci_strong_sell_threshold:
|
|
df['cci_rating'] = 'Strong Sell'
|
|
elif cci_strong_sell_threshold <= df['cci'].iloc[-1] < cci_sell_threshold:
|
|
df['cci_rating'] = 'Sell'
|
|
elif cci_sell_threshold <= df['cci'].iloc[-1] < cci_buy_threshold:
|
|
df['cci_rating'] = 'Neutral'
|
|
elif cci_buy_threshold <= df['cci'].iloc[-1] < cci_strong_buy_threshold:
|
|
df['cci_rating'] = 'Buy'
|
|
else:
|
|
df['cci_rating'] = 'Strong Buy'
|
|
|
|
|
|
|
|
res_list = [
|
|
{'name': 'Relative Strength Index (14)', 'value': round(df['rsi'].iloc[-1],2), 'signal': df['rsi_rating'].iloc[-1]},
|
|
{'name': 'Stochastic RSI Fast (3,3,14,14)', 'value': round(df['stoch_rsi'].iloc[-1],2), 'signal': df['stoch_rsi_rating'].iloc[-1]},
|
|
{'name': 'Money Flow Index (14)', 'value': round(df['mfi'].iloc[-1],2), 'signal': df['mfi_rating'].iloc[-1]},
|
|
{'name': 'Simple Moving Average (20)', 'value': round(df['sma_20'].iloc[-1],2), 'signal': df['sma_rating'].iloc[-1]},
|
|
{'name': 'Exponential Moving Average (20)', 'value': round(df['ema_20'].iloc[-1],2), 'signal': df['ema_rating'].iloc[-1]},
|
|
{'name': 'Weighted Moving Average (20)', 'value': round(df['wma'].iloc[-1],2), 'signal': df['wma_rating'].iloc[-1]},
|
|
{'name': 'Average Directional Index (14)', 'value': round(df['adx'].iloc[-1],2), 'signal': df['adx_rating'].iloc[-1]},
|
|
{'name': 'Commodity Channel Index (14)', 'value': round(df['cci'].iloc[-1],2), 'signal': df['cci_rating'].iloc[-1]},
|
|
{'name': 'Rate of Change (12)', 'value': round(df['roc'].iloc[-1],2), 'signal': df['roc_rating'].iloc[-1]},
|
|
{'name': 'Moving Average Convergence Divergence (12, 26)', 'value': round(df['macd'].iloc[-1],2), 'signal': df['macd_rating'].iloc[-1]},
|
|
{'name': 'Williams %R (14)', 'value': round(df['williams'].iloc[-1],2), 'signal': df['williams_rating'].iloc[-1]}
|
|
]
|
|
|
|
overall_signal = self.compute_overall_signal(res_list)
|
|
|
|
res_dict = {'overallSignal': overall_signal, 'signalList': res_list}
|
|
return res_dict
|
|
|
|
# Load the historical stock price data
|
|
|
|
|
|
|
|
|
|
|
|
#Testing mode
|
|
# Load the data
|
|
'''
|
|
import sqlite3
|
|
start_date = "2015-01-01"
|
|
end_date = datetime.today().strftime("%Y-%m-%d")
|
|
con = sqlite3.connect('stocks.db')
|
|
symbol = 'ZTS'
|
|
|
|
query_template = """
|
|
SELECT
|
|
date, open, high, low, close, volume
|
|
FROM
|
|
"{symbol}"
|
|
WHERE
|
|
date BETWEEN ? AND ?
|
|
"""
|
|
query = query_template.format(symbol=symbol)
|
|
df = pd.read_sql_query(query, con, params=(start_date, end_date))
|
|
|
|
test = rating_model(df).ta_rating()
|
|
print(test)
|
|
con.close()
|
|
''' |