- 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:
+122
-83
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user