- refactored

- cleaned up
- added buy agent

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