- avoid pandas for data arrays

-  use more numpy consequently

git-svn-id: http://moon:8086/svn/projects/Stock@324 fda53097-d464-4ada-af97-ba876c37ca34
This commit is contained in:
2019-12-22 22:38:58 +00:00
parent 6245198667
commit a34c4d1d2f
+122 -83
View File
@@ -6,9 +6,7 @@ import matplotlib.pyplot as plt
from scipy.interpolate import UnivariateSpline from scipy.interpolate import UnivariateSpline
import datetime as dt import datetime as dt
import os import os
import matplotlib as mpl 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
@@ -24,21 +22,21 @@ mpl.rc('figure', max_open_warning = 0)
# 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
show_range_days = 40 show_range_days = 40
show_symbols = ['OHB.DE', 'ITMPF', 'PLUG', 'MOR.DE', 'CSCO', 'ERCA.DE', 'AVGO', 'DIS', 'UBSFF', 'DHER.DE', 'AIR'] show_symbols = ['OHB.DE', 'ITMPF', 'PLUG', 'MOR.DE', 'CSCO', 'ERCA.DE', 'AVGO', 'DIS', 'UBSFF', 'DHER.DE', 'AIR']
#show_symbols = ['CSCO'] show_symbols = ['CSCO']
#show_symbols = ['OHB.DE'] #show_symbols = ['OHB.DE']
#show_symbols = ['UBSFF'] #show_symbols = ['UBSFF']
#show_symbols = ['DHER.DE'] #show_symbols = ['DHER.DE']
show_symbols = ['WDI.DE']
show_symbols = [] show_symbols = []
k_euro = 1 / 1.11 k_euro = 1 / 1.11
N_poly = 7
ema_alpha = 0.75 ema_alpha = 0.75
sma_days = 10 sma_days = 10
q_days = 10
fetch_on_outdated = True fetch_on_outdated = True
mpl.rc('figure', max_open_warning = 0)
symbols = { symbols = {
'WDI.DE' : {'name' : 'WireCard', 'currency' : ''}, 'WDI.DE' : {'name' : 'WireCard', 'currency' : ''},
@@ -120,22 +118,25 @@ symbols = {
'I' : {'name': 'IntelSat', 'currency' : '$'}} 'I' : {'name': 'IntelSat', 'currency' : '$'}}
def exponential_moving_average(data, key, alpha=0.5, ic=None): def exponential_moving_average(data, key, alpha=0.5, ic=None):
result = [] result = np.zeros_like(data[key])
if ic is None: if ic is None:
r = data[key][0] r = data[key][0]
else: else:
r = ic r = ic
n = 0
for v in data[key]: for v in data[key]:
r = alpha*r + (1-alpha)*v r = alpha*r + (1-alpha)*v
result.append(r) result[n] = r
n += 1
return np.array(result) return np.array(result)
def moving_average(data, key, window_days, ic=0): def moving_average(data, key, window_days, ic=0):
mem = [ic] * window_days mem = [ic] * window_days
result = [] result = np.zeros_like(data[key])
k=0 k=0
cumsum = ic cumsum = ic
n = 0
for v in data[key]: for v in data[key]:
cumsum += (v - mem[k]) cumsum += (v - mem[k])
mem[k] = v mem[k] = v
@@ -143,18 +144,23 @@ def moving_average(data, key, window_days, ic=0):
if k >= window_days: if k >= window_days:
k=0 k=0
result.append(cumsum/window_days) result[n] = cumsum/window_days
n += 1
return result return result
def moving_variance(data, key, window_days, ic=0): def moving_variance(data, key, window_days, ic=0):
mem = [ic] * window_days mem = [ic] * window_days
result = [] result = np.zeros_like(data[key])
k=0 k=0
cumsum = ic cumsum = ic
data_mean = data[key] - moving_average(data, key, window_days, ic) data_mean = data[key] - moving_average(data, key, window_days, ic)
n = 0
for v in data_mean: for v in data_mean:
v2 = v * v try:
v2 = v * v
except:
print ('v', v)
cumsum += (v2 - mem[k]) cumsum += (v2 - mem[k])
mem[k] = v2 mem[k] = v2
k += 1 k += 1
@@ -162,55 +168,60 @@ def moving_variance(data, key, window_days, ic=0):
k=0 k=0
var = max(0, cumsum) / window_days var = max(0, cumsum) / window_days
result.append(math.sqrt(var)) result[n] = math.sqrt(var)
n += 1
return result return result
def moving_max(data, key, window_days, ic=-1e9): def moving_max(data, key, window_days, ic=-1e9):
mem = [ic] * window_days mem = [ic] * window_days
result = [] result = np.zeros_like(data[key])
k=0 k=0
n = 0
for v in data[key]: for v in data[key]:
mem[k] = v mem[k] = v
k += 1 k += 1
if k >= window_days: if k >= window_days:
k=0 k=0
_max = np.max(mem) result[n] = np.max(mem)
result.append(_max) n += 1
return result return result
def moving_min(data, key, window_days, ic=1e9): def moving_min(data, key, window_days, ic=1e9):
mem = [ic] * window_days mem = [ic] * window_days
result = [] result = np.zeros_like(data[key])
k=0 k=0
n = 0
for v in data[key]: for v in data[key]:
mem[k] = v mem[k] = v
k += 1 k += 1
if k >= window_days: if k >= window_days:
k=0 k=0
_min = np.min(mem) result[n] = np.min(mem)
result.append(_min) n += 1
return result return result
def normalize(data, key, ic=None): def normalize(data, key, ic=None):
result = [] result = np.zeros_like(data[key])
if ic is None: if ic is None:
prev = data[key][0] prev = data[key][0]
else: else:
prev = ic prev = ic
n = 0
for v in data[key]: for v in data[key]:
v_n = (v - prev)/prev v_n = (v - prev)/prev
result.append(100*v_n) result[n] = 100*v_n
n += 1
return result return result
def colsum(data, keys): def colsum(data, keys):
result = np.zeros(data.shape[0]) result = np.zeros(data['index'].shape)
for key in keys: for key in keys:
result += data[key] result += data[key]
@@ -223,39 +234,39 @@ def macd(data, key):
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 = colsum(data, keys=['high', 'low', 'close']) / 3
tp_df = tp_ser.to_frame(name='tp') tp_dict = {'tp': tp}
stddev = np.array(moving_variance(tp_df, 'tp', window_days)) stddev = np.array(moving_variance(tp_dict, 'tp', window_days))
mid = np.array(moving_average(tp_df, key='tp', window_days=window_days)) mid = np.array(moving_average(tp_dict, 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 = {'index' : data['index'], 'upper' : upper, 'mid' : mid, 'lower' : lower}
result['lower'] = lower
result['mid'] = mid
return result return result
def agent_buy(name, data, thresh_max=-10, thresh_min=1): def agent_buy(name, data, cand_window, thresh_max=-10, thresh_min=1):
buy_list = [] N = len(data['index'])
buy_list = np.array([None]*N)
cand = None cand = None
for n in range(0, len(data.index)): for n in range(0, len(data['index'])):
vmax = data['Qmax'][n] vmax = data['Qmax'][n]
vmin = data['Qmin'][n] vmin = data['Qmin'][n]
trend = data['macd_fd'][n] trend = data['macd_fd'][n]
index = data.index[n]
if vmin <= thresh_min: if vmin <= thresh_min:
if vmax <= thresh_max: if vmax <= thresh_max:
cand = n cand = n
if trend >= 0: if trend >= 0:
print ("{}: Buy on {}".format(name, index)) print ("{}: Buy on {} at {:0.2f}%".format(name, data['index'][cand], data['close_n'][cand]))
buy_list.append({'name': name, 'date': index}) y = data['close_n'][n]
buy_list[n] = y
cand = None cand = None
if cand is not None: if cand is not None:
if n - cand >= 5: if n - cand <= cand_window:
if trend >= 0: if trend >= 0:
print("{}: Delayed buy on {}".format(name, data.index[cand])) print("{}: Delayed buy on {}".format(name, data['index'][n]))
buy_list.append({'name': name, 'date': data.index[cand]}) y = data['close_n'][n]
buy_list[n] = y
cand = None cand = None
return buy_list return buy_list
@@ -275,6 +286,9 @@ class Title(object):
if '$' in self.currency: if '$' in self.currency:
self.currency_corr = k_euro self.currency_corr = k_euro
self.data = {}
self.boll = {}
self.indicators = {}
def fetch(self): def fetch(self):
filename = self.symbol.replace('.', '_') + '.h5' filename = self.symbol.replace('.', '_') + '.h5'
@@ -304,79 +318,103 @@ class Title(object):
else: else:
hdf = pd.HDFStore(filename, 'r') hdf = pd.HDFStore(filename, 'r')
self.data_full = hdf[self.symbol] * self.currency_corr data = hdf[self.symbol] * self.currency_corr
self.data['index'] = np.array(data.index)
self.data['close'] = np.array(data['close'])
self.data['high'] = np.array(data['high'])
self.data['low'] = np.array(data['low'])
hdf.close() hdf.close()
def __plot(self, d, keys):
dates = d.index
for key in keys:
data = d[key]
data.plot()
def hover(event):
if event.inaxes == self.ax:
x_idx = int(event.xdata)
self.ax.format_xdata = lambda x: dates[x_idx]
self.ax.format_ydata = lambda y: '{:.2f}'.format(data[x_idx])
self.fig.canvas.mpl_connect("motion_notify_event", hover)
def analyze(self): def analyze(self):
N = len(self.data_full['close']) N = len(self.data['index'])
self.data_full['ema'] = exponential_moving_average(self.data_full, key='close', alpha=ema_alpha) self.data['ema'] = exponential_moving_average(self.data, key='close', alpha=ema_alpha)
self.data_full['macd'] = macd(self.data_full, key='close') self.data['sma'] = moving_average(self.data, key='close', window_days=sma_days)
self.data_full['sma'] = moving_average(self.data_full, key='close', window_days=sma_days) self.data['close_n'] = normalize(self.data, key='close')
self.data_full['close_n'] = normalize(self.data_full, key='close') self.data['macd'] = macd(self.data, key='close_n')
self.data_full['min'] = moving_min(self.data_full, key='close_n', window_days=q_days) self.data['min'] = moving_min(self.data, 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['max'] = moving_max(self.data, key='close_n', window_days=q_days)
self.data_full['Qmin'] = self.data_full['close_n'] - self.data_full['min'] self.data['Qmin'] = self.data['close_n'] - self.data['min']
self.data_full['Qmax'] = self.data_full['close_n'] - self.data_full['max'] self.data['Qmax'] = self.data['close_n'] - self.data['max']
self.boll_full = bollinger(self.data_full, window_days=30) self.boll = bollinger(self.data, window_days=30)
x_r = np.linspace(0, N, N) x_r = np.linspace(0, N, N)
y_r = self.data_full['macd'].to_numpy() y_r = self.data['macd']
spl = UnivariateSpline(x_r, y_r) spl = UnivariateSpline(x_r, y_r)
spl.set_smoothing_factor(0.5) spl.set_smoothing_factor(0.25)
yf = spl(x_r) yf = spl(x_r)
yf_d = spl.derivative()(x_r) yf_d = spl.derivative()(x_r)
self.data_full['macd_f'] = pd.DataFrame(np.transpose([yf]), index=self.data_full['macd'].index, columns=['macd_fitted']) self.data['macd_f'] = np.transpose(yf)
self.data_full['macd_fd'] = pd.DataFrame(np.transpose([yf_d]), index=self.data_full['macd'].index, columns=['macd_fitted_d']) self.data['macd_fd'] = np.transpose(yf_d)
_macd_f_curr = self.data_full['macd_f'][N-1] self.data['Buy'] = agent_buy(self.symbol, self.data, cand_window=q_days)
_macd_fd_curr = self.data_full['macd_fd'][N-1]
self.data = self.data_full[len(self.data_full) - show_range_days:] @staticmethod
self.boll = self.boll_full[len(self.boll_full) - show_range_days:] def slice(data, start, stop):
result = {}
for key in iter(data):
result[key] = data[key][start:stop]
return result
def __plot(self, data, keys):
N = len(data['index'])
start = max(0, N - show_range_days)
stop = N
xr = list(range(start, stop))
sliced = Title.slice(data, start, stop)
for key in keys:
plt.plot(xr, sliced[key], label=key)
return agent_buy(self.symbol, self.data) def hover(event):
if event.inaxes == self.ax:
x_idx = min(N-1, int(event.xdata))
self.ax.format_xdata = lambda x: self.data['index'][x_idx]
self.ax.format_ydata = lambda y: '{:.2f}%'.format(self.data['close_n'][x_idx])
self.fig.canvas.mpl_connect("motion_notify_event", hover)
def __ind(self, data, keys):
N = len(data['index'])
start = max(0, N - show_range_days)
stop = N
xr = list(range(start, stop))
sliced = Title.slice(data, start, stop)
for key in keys:
plt.plot(xr, sliced[key], 'go', label=key)
def has_candidate(self, key, range_days):
N = len(self.data['index'])
start = max(0, N - range_days)
stop = N
sliced = Title.slice(self.data, start, stop)
result = np.count_nonzero(sliced[key] != None)
return result > 0
def show(self, figNum=1): def show(self, figNum=1):
self.fig = plt.figure(figNum) self.fig = plt.figure(figNum)
self.ax = plt.subplot(311) self.ax = plt.subplot(311)
self.__plot(self.data, ['min', 'max', 'close_n']) self.__plot(self.data, ['min', 'max', 'close_n'])
self.__ind(self.data, ['Buy'])
plt.title('{} ({})'.format(self.name, self.symbol)) plt.title('{} ({})'.format(self.name, self.symbol))
plt.legend() plt.legend()
plt.grid() plt.grid()
plt.subplot(312) plt.subplot(312)
# self.boll['upper'].plot() # self.__plot(self.boll, ['lower', 'mid', 'upper'])
# self.boll['mid'].plot() self.__plot(self.data, ['Qmin', 'Qmax'])
# 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.data['macd_f'].plot() self.__plot(self.data, ['macd', 'macd_f', 'macd_fd'])
self.data['macd_fd'].plot()
plt.legend() plt.legend()
plt.grid() plt.grid()
@@ -390,15 +428,16 @@ if len(show_symbols) > 0:
title = Title(symbol, symbols[symbol]) title = Title(symbol, symbols[symbol])
title.fetch() title.fetch()
title.analyze() title.analyze()
title.show(figNum) title.show(figNum=figNum)
figNum += 1 figNum += 1
else: else:
for symbol in symbols: for symbol in symbols:
print('-----------------------------------------------') print('-----------------------------------------------')
title = Title(symbol, symbols[symbol]) title = Title(symbol, symbols[symbol])
title.fetch() title.fetch()
if len(title.analyze()) > 0: title.analyze()
title.show(figNum) if title.has_candidate(key='Buy', range_days=show_range_days):
title.show(figNum=figNum)
figNum += 1 figNum += 1
plt.show() plt.show()