From a673d678b565b19df06a2d20a77a76af23eb35d0 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sun, 22 Dec 2019 13:19:54 +0000 Subject: [PATCH] - refactored - cleaned up - added buy agent git-svn-id: http://moon:8086/svn/projects/Stock@322 fda53097-d464-4ada-af97-ba876c37ca34 --- pandas_eval.py | 243 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 164 insertions(+), 79 deletions(-) diff --git a/pandas_eval.py b/pandas_eval.py index 7ba2cc2..fae7edd 100644 --- a/pandas_eval.py +++ b/pandas_eval.py @@ -7,6 +7,9 @@ from scipy.interpolate import UnivariateSpline import datetime as dt import os +import matplotlib as mpl +mpl.rc('figure', max_open_warning = 0) + # Stock Investors Financial Math # https://www.fmlabs.com/reference/default.htm?url=SimpleMA.htm @@ -21,14 +24,21 @@ import os # https://ntguardian.wordpress.com/2016/09/19/introduction-stock-market-data-python-1 key = '0UO7Z2MVZ2YSQSVE' +q_days = 20 thresh_macd = 1.5 -show_range_days = 20 -show_symbols = ['ITMPF', 'PLUG', 'MOR.DE', 'CSCO', 'ERCA.DE', 'AVGO', 'DIS'] -#show_symbols = [] +show_range_days = 40 +show_symbols = ['OHB.DE', 'ITMPF', 'PLUG', 'MOR.DE', 'CSCO', 'ERCA.DE', 'AVGO', 'DIS', 'UBSFF', 'DHER.DE', 'AIR'] +#show_symbols = ['CSCO'] +#show_symbols = ['OHB.DE'] +#show_symbols = ['UBSFF'] +#show_symbols = ['DHER.DE'] +show_symbols = [] k_euro = 1 / 1.11 N_poly = 7 ema_alpha = 0.75 sma_days = 10 +fetch_on_outdated = True + symbols = { 'WDI.DE' : {'name' : 'WireCard', 'currency' : '€'}, @@ -52,64 +62,64 @@ symbols = { 'FB2A.DE' : {'currency' : '€'}, 'ZIL2.DE' : {'currency' : '€'}, 'SIS.DE' : {'currency' : '€'}, - 'SIE.DE' : {'currency' : '€'}, + 'SIE.DE' : {'name': 'Siemens', 'currency' : '€'}, 'GFT.DE' : {'currency' : '€'}, - 'AMD.DE' : {'currency' : '€'}, - 'CAP.DE' : {'currency' : '€'}, - 'ADBE' : {'currency' : '$'}, - 'PANW' : {'currency' : '$'}, - 'AMAT' : {'currency' : '$'}, - 'RIB.DE' : {'currency' : '€'}, - 'WAF.DE' : {'currency' : '€'}, - 'EVT.DE' : {'currency' : '€'}, - 'VOW.DE' : {'currency' : '€'}, - 'BMW.DE' : {'currency' : '€'}, - 'NSU.DE' : {'currency' : '€'}, - 'DAI.DE' : {'currency' : '€'}, - 'SHA.DE' : {'currency' : '€'}, - 'CON.DE' : {'currency' : '€'}, + 'AMD.DE' : {'name': 'Advanced Micro Devices', 'currency' : '€'}, + 'CAP.DE' : {'name': 'Encavis', 'currency' : '€'}, + 'ADBE' : {'name': 'Adobe', 'currency' : '$'}, + 'PANW' : {'name': 'Palo Alto Networks', 'currency' : '$'}, + 'AMAT' : {'name': 'Applied Materials', 'currency' : '$'}, + 'RIB.DE' : {'name': 'RIB Software', 'currency' : '€'}, + 'WAF.DE' : {'name': 'Siltronic', 'currency' : '€'}, + 'EVT.DE' : {'name': 'Evotec', 'currency' : '€'}, + 'VOW.DE' : {'name': 'Volkswagen', 'currency' : '€'}, + 'BMW.DE' : {'name': 'BMW', 'currency' : '€'}, + 'NSU.DE' : {'name': 'Audi', 'currency' : '€'}, + 'DAI.DE' : {'name': 'Daimler', 'currency' : '€'}, + 'SHA.DE' : {'name': 'Schaeffler', 'currency' : '€'}, + 'CON.DE' : {'name': 'Continental', 'currency' : '€'}, 'DHER.DE' : {'name' : 'Delivery Hero', 'currency' : '€'}, - 'BSL.DE' : {'currency' : '€'}, + 'BSL.DE' : {'name': 'Basler', 'currency' : '€'}, 'D6H.DE' : {'currency' : '€'}, 'TC1.DE' : {'currency' : '€'}, 'VODI.DE' : {'currency' : '€'}, 'ATVI' : {'currency' : '$'}, 'GME' : {'currency' : '$'}, - 'NTO.F' : {'currency' : '$'}, - 'UBSFF' : {'currency' : '$'}, - 'NXPRF' : {'currency' : '$'}, - 'IMPUF' : {'currency' : '$'}, - 'NMPNF' : {'currency' : '$'}, - 'ALSMY' : {'currency' : '$'}, - 'ARRD.F' : {'currency' : '$'}, - 'PHG' : {'currency' : '$'}, - 'KEYS' : {'currency' : '$'}, - 'ORCL' : {'currency' : '$'}, - 'UBER' : {'currency' : '$'}, - 'VMW' : {'currency' : '$'}, + 'NTO.F' : {'name': 'Nintendo', 'currency' : '$'}, + 'UBSFF' : {'name': 'UBI Soft', 'currency' : '$'}, + 'NXPRF' : {'name': 'Nexans', 'currency' : '$'}, + 'IMPUF' : {'name': 'Impala Platinum Holdings', 'currency' : '$'}, + 'NMPNF' : {'name': 'Northam Platinum', 'currency' : '$'}, + 'ALSMY' : {'name': 'Alstom', 'currency' : '$'}, + 'ARRD.F' : {'name': 'Arcelor Mittal', 'currency' : '$'}, + 'PHG' : {'name': 'Philips', 'currency' : '$'}, + 'KEYS' : {'name': 'KeySight', 'currency' : '$'}, + 'ORCL' : {'name': 'Oracle', 'currency' : '$'}, + 'UBER' : {'name': 'Uber', 'currency' : '$'}, + 'VMW' : {'name': 'VMWare', 'currency' : '$'}, 'AVGO' : {'name' : 'Avago', 'currency' : '$'}, - 'CY' : {'currency' : '$'}, - 'QABSY' : {'currency' : '$'}, - 'BLDP' : {'currency' : '$'}, - 'D7G.F' : {'currency' : '$'}, - 'ITMPF' : {'currency' : '$'}, - 'PLUG' : {'currency' : '$'}, - 'PCELF' : {'currency' : '$'}, + 'CY' : {'name': 'Cypress Semiconductor', 'currency' : '$'}, + 'QABSY' : {'name': 'Qanta Airways', 'currency' : '$'}, + 'BLDP' : {'name': 'Ballard Power', 'currency' : '$'}, + 'D7G.F' : {'name': 'Nel ASA', 'currency' : '$'}, + 'ITMPF' : {'name': 'ITM Power', 'currency' : '$'}, + 'PLUG' : {'name': 'PlugPower', 'currency' : '$'}, + 'PCELF' : {'name': 'PowerCell', 'currency' : '$'}, 'SU.PA' : {'currency' : '$'}, # 'SON1.DE' : {'currency' : '€'}, - 'STM.DE' : {'currency' : '€'}, - 'BC8.DE' : {'currency' : '€'}, + 'STM.DE' : {'name': 'STM Micro', 'currency' : '€'}, + 'BC8.DE' : {'name': 'Bechtle', 'currency' : '€'}, 'MOR.DE' : {'name' : 'Morphosys', 'currency' : '€'}, 'BAYN.DE' : {'currency' : '€'}, 'BEI.DE' : {'currency' : '€'}, 'EUZ.DE' : {'currency' : '€'}, - 'SLAB' : {'currency' : '$'}, + 'SLAB' : {'name': 'Silicon Laboratories', 'currency' : '$'}, 'SPLK' : {'name' : 'Splunk', 'currency' : '$'}, 'IAG' : {'name' : 'IAG', 'currency' : '$'}, 'INTC' : {'currency' : '$'}, - 'I' : {'currency' : '$'}} + 'I' : {'name': 'IntelSat', 'currency' : '$'}} -def ema(data, key, alpha=0.5, ic=None): +def exponential_moving_average(data, key, alpha=0.5, ic=None): result = [] if ic is None: r = data[key][0] @@ -121,11 +131,11 @@ def ema(data, key, alpha=0.5, ic=None): return np.array(result) -def sma(data, key, window_days, ic=None): - mem = [0] * window_days +def moving_average(data, key, window_days, ic=0): + mem = [ic] * window_days result = [] k=0 - cumsum = 0 + cumsum = ic for v in data[key]: cumsum += (v - mem[k]) mem[k] = v @@ -137,12 +147,12 @@ def sma(data, key, window_days, ic=None): return result -def sd(data, key, window_days, ic=None): - mem = [0] * window_days +def moving_variance(data, key, window_days, ic=0): + mem = [ic] * window_days result = [] k=0 - cumsum = 0 - data_mean = data[key] - sma(data, key, window_days, ic) + cumsum = ic + data_mean = data[key] - moving_average(data, key, window_days, ic) for v in data_mean: v2 = v * v cumsum += (v2 - mem[k]) @@ -156,6 +166,48 @@ def sd(data, key, window_days, ic=None): return result +def moving_max(data, key, window_days, ic=-1e9): + mem = [ic] * window_days + result = [] + k=0 + for v in data[key]: + mem[k] = v + k += 1 + if k >= window_days: + k=0 + + _max = np.max(mem) + result.append(_max) + + return result + +def moving_min(data, key, window_days, ic=1e9): + mem = [ic] * window_days + result = [] + k=0 + for v in data[key]: + mem[k] = v + k += 1 + if k >= window_days: + k=0 + + _min = np.min(mem) + result.append(_min) + + return result + +def normalize(data, key, ic=None): + result = [] + if ic is None: + prev = data[key][0] + else: + prev = ic + for v in data[key]: + v_n = (v - prev)/prev + result.append(100*v_n) + + return result + def colsum(data, keys): result = np.zeros(data.shape[0]) @@ -165,17 +217,17 @@ def colsum(data, keys): return result def macd(data, key): - ema_short = ema(data, key, alpha=0.85) - ema_long = ema(data, key, alpha=0.925) + ema_short = exponential_moving_average(data, key, alpha=0.85) + ema_long = exponential_moving_average(data, key, alpha=0.925) return ema_short - ema_long def bollinger(data, window_days, f=2): tp_ser = colsum(data, keys=['high', 'low', 'close']) / 3 tp_df = tp_ser.to_frame(name='tp') - stddev = np.array(sd(tp_df, 'tp', window_days)) + stddev = np.array(moving_variance(tp_df, 'tp', window_days)) - mid = np.array(sma(tp_df, key='tp', window_days=window_days)) + mid = np.array(moving_average(tp_df, key='tp', window_days=window_days)) upper = mid + f * stddev lower = mid - f * stddev result = pd.DataFrame(upper, index=data.index, columns=['upper']) @@ -183,6 +235,31 @@ def bollinger(data, window_days, f=2): result['mid'] = mid return result +def agent_buy(name, data, thresh_max=-10, thresh_min=1): + buy_list = [] + cand = None + for n in range(0, len(data.index)): + vmax = data['Qmax'][n] + vmin = data['Qmin'][n] + trend = data['macd_fd'][n] + index = data.index[n] + if vmin <= thresh_min: + if vmax <= thresh_max: + cand = n + if trend >= 0: + print ("{}: Buy on {}".format(name, index)) + buy_list.append({'name': name, 'date': index}) + cand = None + + if cand is not None: + if n - cand >= 5: + if trend >= 0: + print("{}: Delayed buy on {}".format(name, data.index[cand])) + buy_list.append({'name': name, 'date': data.index[cand]}) + cand = None + + return buy_list + class Title(object): def __init__(self, symbol, params): self.symbol = symbol @@ -212,7 +289,7 @@ class Title(object): try: lastmodified = dt.datetime.fromtimestamp(os.stat(filename).st_mtime).date() if lastmodified != today: - fetch = True + fetch = fetch_on_outdated except: fetch = True @@ -246,52 +323,60 @@ class Title(object): self.fig.canvas.mpl_connect("motion_notify_event", hover) def analyze(self): - self.data_full['ema'] = ema(self.data_full, key='close', alpha=ema_alpha) + N = len(self.data_full['close']) + self.data_full['ema'] = exponential_moving_average(self.data_full, key='close', alpha=ema_alpha) self.data_full['macd'] = macd(self.data_full, key='close') - self.data_full['sma'] = sma(self.data_full, key='close', window_days=sma_days) + self.data_full['sma'] = moving_average(self.data_full, key='close', window_days=sma_days) + self.data_full['close_n'] = normalize(self.data_full, key='close') + self.data_full['min'] = moving_min(self.data_full, key='close_n', window_days=q_days) + self.data_full['max'] = moving_max(self.data_full, key='close_n', window_days=q_days) + + self.data_full['Qmin'] = self.data_full['close_n'] - self.data_full['min'] + self.data_full['Qmax'] = self.data_full['close_n'] - self.data_full['max'] self.boll_full = bollinger(self.data_full, window_days=30) - _macd_curr = self.data_full['macd'][len(self.data_full)-1] - - self._macd_data = self.data_full['macd'][len(self.data_full) - show_range_days:] - x_r = np.linspace(0, len(self._macd_data), len(self._macd_data)) - y_r = self._macd_data.to_numpy() + x_r = np.linspace(0, N, N) + y_r = self.data_full['macd'].to_numpy() spl = UnivariateSpline(x_r, y_r) spl.set_smoothing_factor(0.5) yf = spl(x_r) yf_d = spl.derivative()(x_r) - self._macd_fitted = pd.DataFrame(np.transpose([yf,yf_d]), index=self._macd_data.index, columns=['macd_fitted', 'macd_fitted_d']) + self.data_full['macd_f'] = pd.DataFrame(np.transpose([yf]), index=self.data_full['macd'].index, columns=['macd_fitted']) + self.data_full['macd_fd'] = pd.DataFrame(np.transpose([yf_d]), index=self.data_full['macd'].index, columns=['macd_fitted_d']) - _macd_f_curr = self._macd_fitted['macd_fitted'][len(self._macd_fitted)-1] - _macd_fd_curr = self._macd_fitted['macd_fitted_d'][len(self._macd_fitted)-1] + _macd_f_curr = self.data_full['macd_f'][N-1] + _macd_fd_curr = self.data_full['macd_fd'][N-1] - return {'macd' : _macd_curr, 'macd_f' : _macd_f_curr, 'macd_fd' : _macd_fd_curr} + self.data = self.data_full[len(self.data_full) - show_range_days:] + self.boll = self.boll_full[len(self.boll_full) - show_range_days:] + + + return agent_buy(self.symbol, self.data) def show(self, figNum=1): - data = self.data_full[len(self.data_full) - show_range_days:] - boll = self.boll_full[len(self.boll_full) - show_range_days:] self.fig = plt.figure(figNum) self.ax = plt.subplot(311) - self.__plot(data, ['ema', 'sma', 'close']) - plt.title(self.name) + self.__plot(self.data, ['min', 'max', 'close_n']) + plt.title('{} ({})'.format(self.name, self.symbol)) plt.legend() plt.grid() plt.subplot(312) - boll['upper'].plot() - boll['mid'].plot() - boll['lower'].plot() +# self.boll['upper'].plot() +# self.boll['mid'].plot() +# self.boll['lower'].plot() + self.data['Qmin'].plot() + self.data['Qmax'].plot() plt.legend() plt.grid() plt.subplot(313) - self._macd_data.plot() - self._macd_fitted['macd_fitted'].plot() - self._macd_fitted['macd_fitted_d'].plot() + self.data['macd_f'].plot() + self.data['macd_fd'].plot() plt.legend() plt.grid() @@ -304,15 +389,15 @@ if len(show_symbols) > 0: if symbol in symbols: title = Title(symbol, symbols[symbol]) title.fetch() - print(title.analyze()) + title.analyze() title.show(figNum) figNum += 1 else: for symbol in symbols: + print('-----------------------------------------------') title = Title(symbol, symbols[symbol]) title.fetch() - result = title.analyze() - if result['macd_f'] > thresh_macd and result['macd_fd'] > 0: + if len(title.analyze()) > 0: title.show(figNum) figNum += 1