Classes implemented in python and javascript. UML class diagram. Rough sequence uml. TODO: local file getting dirty from refresh. Signals ready for implementation.
This commit is contained in:
parent
0a49a52383
commit
de4686b109
|
|
@ -27,9 +27,6 @@ class Configuration:
|
||||||
# The data that will be saved and loaded from file .
|
# The data that will be saved and loaded from file .
|
||||||
self.saved_data = None
|
self.saved_data = None
|
||||||
|
|
||||||
def set_indicator_list(self, list):
|
|
||||||
self.indicator_list = list
|
|
||||||
|
|
||||||
def config_and_states(self, cmd):
|
def config_and_states(self, cmd):
|
||||||
"""Loads or saves configurable data to the file set in self.config_FN"""
|
"""Loads or saves configurable data to the file set in self.config_FN"""
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
7
app.py
7
app.py
|
|
@ -148,7 +148,8 @@ def settings():
|
||||||
|
|
||||||
if 'delete' in request.form:
|
if 'delete' in request.form:
|
||||||
indicator = request.form['delete']
|
indicator = request.form['delete']
|
||||||
del bt.app_data.indicators.indicator_list[indicator]
|
# This will delete in both indicators and config.
|
||||||
|
bt.app_data.indicators.delete_indicator(indicator)
|
||||||
# Redirect without reloading history
|
# Redirect without reloading history
|
||||||
bt.app_data.config.config_and_states('save')
|
bt.app_data.config.config_and_states('save')
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
|
|
@ -170,8 +171,10 @@ def settings():
|
||||||
if value.isdigit():
|
if value.isdigit():
|
||||||
value = int(value)
|
value = int(value)
|
||||||
properties[key] = value
|
properties[key] = value
|
||||||
|
# Should create in indicators and update the list in config.
|
||||||
bt.app_data.indicators.create_indicator(name=indcr, itype=indtyp, properties=properties)
|
bt.app_data.indicators.create_indicator(name=indcr, itype=indtyp, properties=properties)
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print('ERROR SETTING VALUE')
|
print('ERROR SETTING VALUE')
|
||||||
print(f'The string received by the server was: /n{request.form}')
|
print(f'The string received by the server was: /n{request.form}')
|
||||||
|
|
@ -199,5 +202,5 @@ def saved_data():
|
||||||
def indicator_init():
|
def indicator_init():
|
||||||
symbol = bt.app_data.config.trading_pair
|
symbol = bt.app_data.config.trading_pair
|
||||||
interval = bt.app_data.config.chart_interval
|
interval = bt.app_data.config.chart_interval
|
||||||
d = bt.app_data.indicators.get_indicator_data(symbol, interval, 1000)
|
d = bt.app_data.indicators.get_indicator_data(symbol, interval, 800)
|
||||||
return jsonify(d)
|
return jsonify(d)
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,8 @@ class Candles:
|
||||||
# Returns the latest closing values from the class instance.
|
# Returns the latest closing values from the class instance.
|
||||||
if self.latest_close_values:
|
if self.latest_close_values:
|
||||||
if len(self.latest_close_values) < num_record:
|
if len(self.latest_close_values) < num_record:
|
||||||
print('Warning: get_latest_close_values() - Requested too more records then available')
|
print(f'Warning: get_latest_close_values() - Requested {num_record} too more records then available')
|
||||||
|
print(len(self.latest_close_values))
|
||||||
num_record = len(self.latest_close_values)
|
num_record = len(self.latest_close_values)
|
||||||
return self.latest_close_values[-num_record:]
|
return self.latest_close_values[-num_record:]
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
24
config.yml
24
config.yml
|
|
@ -28,9 +28,9 @@ indicator_list:
|
||||||
type: EMA
|
type: EMA
|
||||||
value: 0
|
value: 0
|
||||||
visible: true
|
visible: true
|
||||||
New Indicator4:
|
MACD:
|
||||||
color_1: '#2f1bc6'
|
color_1: '#675c3b'
|
||||||
color_2: '#3e79cb'
|
color_2: '#54fcd6'
|
||||||
fast_p: 12
|
fast_p: 12
|
||||||
hist: 0
|
hist: 0
|
||||||
macd: 0
|
macd: 0
|
||||||
|
|
@ -40,6 +40,12 @@ indicator_list:
|
||||||
type: MACD
|
type: MACD
|
||||||
value: 0
|
value: 0
|
||||||
visible: true
|
visible: true
|
||||||
|
New rsi:
|
||||||
|
color: '#1f8438'
|
||||||
|
period: 10
|
||||||
|
type: RSI
|
||||||
|
value: '38.67'
|
||||||
|
visible: 'True'
|
||||||
RSI 14:
|
RSI 14:
|
||||||
color: '#07120c'
|
color: '#07120c'
|
||||||
period: 14
|
period: 14
|
||||||
|
|
@ -64,14 +70,12 @@ indicator_list:
|
||||||
type: SMA
|
type: SMA
|
||||||
value: 0
|
value: 0
|
||||||
visible: true
|
visible: true
|
||||||
indicator 5:
|
Testing1:
|
||||||
color: '#13cbec'
|
color: '#ffa500'
|
||||||
nameww: valueww
|
|
||||||
period: 20
|
period: 20
|
||||||
test222: 2222222
|
type: RSI
|
||||||
type: LREG
|
value: 0
|
||||||
value: '30302.05'
|
visible: true
|
||||||
visible: 'True'
|
|
||||||
vol:
|
vol:
|
||||||
type: Volume
|
type: Volume
|
||||||
value: 0
|
value: 0
|
||||||
|
|
|
||||||
1
data.py
1
data.py
|
|
@ -75,4 +75,5 @@ class BrighterData:
|
||||||
print(data)
|
print(data)
|
||||||
# TODO lets go!
|
# TODO lets go!
|
||||||
|
|
||||||
|
|
||||||
app_data = BrighterData()
|
app_data = BrighterData()
|
||||||
|
|
|
||||||
677
indicators.py
677
indicators.py
|
|
@ -3,21 +3,330 @@ import numpy as np
|
||||||
import talib
|
import talib
|
||||||
|
|
||||||
|
|
||||||
|
class Indicator:
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
# Initialise all indicators with some default properties.
|
||||||
|
self.name = name
|
||||||
|
self.properties = properties
|
||||||
|
self.properties['type'] = indicator_type
|
||||||
|
if 'value' not in properties:
|
||||||
|
self.properties['value'] = 0
|
||||||
|
if 'visible' not in properties:
|
||||||
|
self.properties['visible'] = True
|
||||||
|
|
||||||
|
|
||||||
|
class Volume(Indicator):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
|
||||||
|
def calculate(self, candles, num_results=800):
|
||||||
|
return candles.get_volume(self.properties['type'])
|
||||||
|
|
||||||
|
|
||||||
|
class SMA(Indicator):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
if 'color' not in properties:
|
||||||
|
self.properties['color'] = f"#{random.randrange(0x1000000):06x}"
|
||||||
|
if 'period' not in properties:
|
||||||
|
self.properties['period'] = 20
|
||||||
|
|
||||||
|
def calculate(self, candles, num_results=800):
|
||||||
|
# These indicators do computations over period number of price data points.
|
||||||
|
# So we need at least that plus what ever amount of results needed.
|
||||||
|
num_cv = self.properties['period'] + num_results
|
||||||
|
closing_data = candles.get_latest_close_values(num_cv)
|
||||||
|
if len(closing_data) < num_cv:
|
||||||
|
print(f'Could not calculate {self.properties["type"]} for time period of {self.properties["period"]}')
|
||||||
|
print('Not enough data available')
|
||||||
|
return
|
||||||
|
# Initialize two arrays to hold a list of closing values and
|
||||||
|
# a list of timestamps associated with these values
|
||||||
|
closes = []
|
||||||
|
ts = []
|
||||||
|
# Isolate all the closing values and timestamps from
|
||||||
|
# the dictionary object
|
||||||
|
for each in closing_data:
|
||||||
|
closes.append(each['close'])
|
||||||
|
ts.append(each['time'])
|
||||||
|
# Convert the list of closes to a numpy array
|
||||||
|
np_real_data = np.array(closes, dtype=float)
|
||||||
|
# Pass the closing values and the period parameter to talib
|
||||||
|
i_values = None
|
||||||
|
if self.properties['type'] == 'SMA':
|
||||||
|
i_values = talib.SMA(np_real_data, self.properties['period'])
|
||||||
|
if self.properties['type'] == 'RSI':
|
||||||
|
i_values = talib.RSI(np_real_data, self.properties['period'])
|
||||||
|
if self.properties['type'] == 'EMA':
|
||||||
|
i_values = talib.EMA(np_real_data, self.properties['period'])
|
||||||
|
if self.properties['type'] == 'LREG':
|
||||||
|
i_values = talib.LINEARREG(np_real_data, self.properties['period'])
|
||||||
|
|
||||||
|
# Combine the new data with the timestamps
|
||||||
|
# Warning: The first <period> of rsi values are <NAN>.
|
||||||
|
# But they should get trimmed off todo get rid of try except *just debugging info
|
||||||
|
try:
|
||||||
|
i_values = i_values[-num_results:]
|
||||||
|
except Exception:
|
||||||
|
raise ValueError(f'error: {self.properties.type} {i_values}')
|
||||||
|
ts = ts[-num_results:]
|
||||||
|
r_data = []
|
||||||
|
for each in range(len(i_values)):
|
||||||
|
r_data.append({'time': ts[each], 'value': i_values[each]})
|
||||||
|
return {"type": self.properties['type'], "data": r_data}
|
||||||
|
|
||||||
|
|
||||||
|
class EMA(SMA):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
|
||||||
|
|
||||||
|
class RSI(SMA):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
|
||||||
|
|
||||||
|
class LREG(SMA):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
|
||||||
|
|
||||||
|
class ATR(SMA):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
|
||||||
|
def calculate(self, candles, num_results=800):
|
||||||
|
# These indicators do computations over period number of price data points.
|
||||||
|
# So we need at least that plus what ever amount of results needed.
|
||||||
|
num_cv = self.properties.period + num_results
|
||||||
|
|
||||||
|
high_data = candles.get_latest_high_values(num_cv)
|
||||||
|
low_data = candles.get_latest_low_values(num_cv)
|
||||||
|
close_data = candles.get_latest_close_values(num_cv)
|
||||||
|
if len(close_data) < num_cv:
|
||||||
|
print(f'Couldn\'t calculate {self.properties.type} for time period of {self.properties.period}')
|
||||||
|
print('Not enough data availiable')
|
||||||
|
return
|
||||||
|
# Initialize 4 arrays to hold a list of h/l/c values and
|
||||||
|
# a list of timestamps associated with these values
|
||||||
|
highs = []
|
||||||
|
lows = []
|
||||||
|
closes = []
|
||||||
|
ts = []
|
||||||
|
# Isolate all the values and timestamps from
|
||||||
|
# the dictionary objects
|
||||||
|
|
||||||
|
for each in high_data:
|
||||||
|
highs.append(each['high'])
|
||||||
|
for each in low_data:
|
||||||
|
lows.append(each['low'])
|
||||||
|
for each in close_data:
|
||||||
|
closes.append(each['close'])
|
||||||
|
ts.append(each['time'])
|
||||||
|
# Convert the lists to a numpy array
|
||||||
|
np_highs = np.array(highs, dtype=float)
|
||||||
|
np_lows = np.array(lows, dtype=float)
|
||||||
|
np_closes = np.array(closes, dtype=float)
|
||||||
|
# Pass the closing values and the period parameter to talib
|
||||||
|
atr = talib.ATR(high=np_highs,
|
||||||
|
low=np_lows,
|
||||||
|
close=np_closes,
|
||||||
|
timeperiod=self.properties.period)
|
||||||
|
# Combine the new data with the timestamps
|
||||||
|
# Warning: The first (<period> -1) of values are <NAN>.
|
||||||
|
# But they should get trimmed off
|
||||||
|
atr = atr[-num_results:]
|
||||||
|
ts = ts[-num_results:]
|
||||||
|
r_data = []
|
||||||
|
for each in range(len(atr)):
|
||||||
|
# filter out nan values
|
||||||
|
if np.isnan(atr[each]):
|
||||||
|
continue
|
||||||
|
r_data.append({'time': ts[each], 'value': atr[each]})
|
||||||
|
return {"type": self.properties.type, "data": r_data}
|
||||||
|
|
||||||
|
|
||||||
|
class BolBands(Indicator):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
ul_col = f"#{random.randrange(0x1000000):06x}"
|
||||||
|
if 'period' not in properties:
|
||||||
|
self.properties['period'] = 50
|
||||||
|
if 'color_1' not in properties:
|
||||||
|
self.properties['color_1'] = ul_col
|
||||||
|
if 'color_2' not in properties:
|
||||||
|
self.properties['color_2'] = f"#{random.randrange(0x1000000):06x}"
|
||||||
|
if 'color_3' not in properties:
|
||||||
|
self.properties['color_3'] = ul_col
|
||||||
|
if 'value1' not in properties:
|
||||||
|
self.properties['value1'] = 0
|
||||||
|
if 'value2' not in properties:
|
||||||
|
self.properties['value2'] = 0
|
||||||
|
if 'value3' not in properties:
|
||||||
|
self.properties['value3'] = 0
|
||||||
|
if 'devup' not in properties:
|
||||||
|
self.properties['devup'] = 2
|
||||||
|
if 'devdn' not in properties:
|
||||||
|
self.properties['devdn'] = 2
|
||||||
|
if 'ma' not in properties:
|
||||||
|
self.properties['ma'] = 1
|
||||||
|
|
||||||
|
def calculate(self, candles, num_results=800):
|
||||||
|
# These indicators do computations over period number of price data points.
|
||||||
|
# So we need at least that plus what ever amount of results needed.
|
||||||
|
# Acceptable values for ma in the talib.BBANDS
|
||||||
|
# {'SMA':0,'EMA':1, 'WMA' : 2, 'DEMA' : 3, 'TEMA' : 4, 'TRIMA' : 5, 'KAMA' : 6, 'MAMA' : 7, 'T3' : 8}
|
||||||
|
num_cv = self.properties['period'] + num_results
|
||||||
|
closing_data = candles.get_latest_close_values(num_cv)
|
||||||
|
if len(closing_data) < num_cv:
|
||||||
|
print(f'Couldn\'t calculate {self.properties["type"]} for time period of {self.properties["period"]}')
|
||||||
|
print('Not enough data availiable')
|
||||||
|
return
|
||||||
|
# Initialize two arrays to hold a list of closing values and
|
||||||
|
# a list of timestamps associated with these values
|
||||||
|
closes = []
|
||||||
|
ts = []
|
||||||
|
# Isolate all the closing values and timestamps from
|
||||||
|
# the dictionary object
|
||||||
|
for each in closing_data:
|
||||||
|
closes.append(each['close'])
|
||||||
|
ts.append(each['time'])
|
||||||
|
# Convert the list of closes to a numpy array
|
||||||
|
np_real_data = np.array(closes, dtype=float)
|
||||||
|
# Pass the closing values and the period parameter to talib
|
||||||
|
upper, middle, lower = talib.BBANDS(np_real_data,
|
||||||
|
timeperiod=self.properties['period'],
|
||||||
|
# number of non-biased standard deviations from the mean
|
||||||
|
nbdevup=self.properties['devup'],
|
||||||
|
nbdevdn=self.properties['devdn'],
|
||||||
|
# Moving average type: simple moving average here
|
||||||
|
matype=self.properties['ma'])
|
||||||
|
|
||||||
|
# Combine the new data with the timestamps
|
||||||
|
# Warning: The first (<period> -1) of values are <NAN>.
|
||||||
|
# But they should get trimmed off
|
||||||
|
i_values_u = upper[-num_results:]
|
||||||
|
i_values_m = middle[-num_results:]
|
||||||
|
i_values_l = lower[-num_results:]
|
||||||
|
ts = ts[-num_results:]
|
||||||
|
r_data_u = []
|
||||||
|
r_data_m = []
|
||||||
|
r_data_l = []
|
||||||
|
for each in range(len(i_values_u)):
|
||||||
|
# filter out nan values
|
||||||
|
if np.isnan(i_values_u[each]):
|
||||||
|
continue
|
||||||
|
r_data_u.append({'time': ts[each], 'value': i_values_u[each]})
|
||||||
|
r_data_m.append({'time': ts[each], 'value': i_values_m[each]})
|
||||||
|
r_data_l.append({'time': ts[each], 'value': i_values_l[each]})
|
||||||
|
r_data = [r_data_u, r_data_m, r_data_l]
|
||||||
|
return {"type": self.properties['type'], "data": r_data}
|
||||||
|
|
||||||
|
|
||||||
|
class MACD(Indicator):
|
||||||
|
def __init__(self, name, indicator_type, properties):
|
||||||
|
super().__init__(name, indicator_type, properties)
|
||||||
|
if 'fast_p' not in properties:
|
||||||
|
self.properties['fast_p'] = 12
|
||||||
|
if 'slow_p' not in properties:
|
||||||
|
self.properties['slow_p'] = 26
|
||||||
|
if 'signal_p' not in properties:
|
||||||
|
self.properties['signal_p'] = 9
|
||||||
|
if 'macd' not in properties:
|
||||||
|
self.properties['macd'] = 0
|
||||||
|
if 'signal' not in properties:
|
||||||
|
self.properties['signal'] = 0
|
||||||
|
if 'hist' not in properties:
|
||||||
|
self.properties['hist'] = 0
|
||||||
|
if 'color_1' not in properties:
|
||||||
|
self.properties['color_1'] = f"#{random.randrange(0x1000000):06x}"
|
||||||
|
if 'color_2' not in properties:
|
||||||
|
self.properties['color_2'] = f"#{random.randrange(0x1000000):06x}"
|
||||||
|
|
||||||
|
def calculate(self, candles, num_results=800):
|
||||||
|
# These indicators do computations over a period number of price data points.
|
||||||
|
# So we need at least that plus what ever amount of results needed.
|
||||||
|
# It seems it needs num_of_nans = (slow_p) - 2) + signal_p
|
||||||
|
|
||||||
|
# TODO: slow_p or fast_p which ever is greater should be used in the calc below.
|
||||||
|
# TODO but i am investigating this.
|
||||||
|
if self.properties['fast_p'] > self.properties['slow_p']:
|
||||||
|
raise ValueError('Error I think: TODO: calculate_macd()')
|
||||||
|
num_cv = (self.properties['slow_p'] - 2) + self.properties['signal_p'] + num_results
|
||||||
|
|
||||||
|
closing_data = candles.get_latest_close_values(num_cv)
|
||||||
|
if len(closing_data) < num_cv:
|
||||||
|
print(f'Couldn\'t calculate {self.properties["type"]} for time period of {self.properties["slow_p"]}')
|
||||||
|
print('Not enough data available')
|
||||||
|
return
|
||||||
|
# Initialize two arrays to hold a list of closing values and
|
||||||
|
# a list of timestamps associated with these values
|
||||||
|
closes = []
|
||||||
|
ts = []
|
||||||
|
# Isolate all the closing values and timestamps from
|
||||||
|
# the dictionary object
|
||||||
|
for each in closing_data:
|
||||||
|
closes.append(each['close'])
|
||||||
|
ts.append(each['time'])
|
||||||
|
# Convert the list of closes to a numpy array
|
||||||
|
np_real_data = np.array(closes, dtype=float)
|
||||||
|
# Pass the closing values and the period parameter to talib
|
||||||
|
macd, signal, hist = talib.MACD(
|
||||||
|
np_real_data,
|
||||||
|
self.properties['fast_p'],
|
||||||
|
self.properties['slow_p'],
|
||||||
|
self.properties['signal_p'])
|
||||||
|
|
||||||
|
# Combine the new data with the timestamps
|
||||||
|
# Warning: The first (<period> -1) of values are <NAN>.
|
||||||
|
# But they should get trimmed off
|
||||||
|
macd = macd[-num_results:]
|
||||||
|
if len(macd) == 1:
|
||||||
|
print('looks like after slicing')
|
||||||
|
print(macd)
|
||||||
|
signal = signal[-num_results:]
|
||||||
|
hist = hist[-num_results:]
|
||||||
|
ts = ts[-num_results:]
|
||||||
|
r_macd = []
|
||||||
|
r_signal = []
|
||||||
|
r_hist = []
|
||||||
|
for each in range(len(macd)):
|
||||||
|
# filter out nan values
|
||||||
|
if np.isnan(macd[each]):
|
||||||
|
continue
|
||||||
|
r_macd.append({'time': ts[each], 'value': macd[each]})
|
||||||
|
r_signal.append({'time': ts[each], 'value': signal[each]})
|
||||||
|
r_hist.append({'time': ts[each], 'value': hist[each]})
|
||||||
|
r_data = [r_macd, r_signal, r_hist]
|
||||||
|
return {"type": self.properties['type'], "data": r_data}
|
||||||
|
|
||||||
|
|
||||||
class Indicators:
|
class Indicators:
|
||||||
def __init__(self, candles, config):
|
def __init__(self, candles, config):
|
||||||
# Object containing Price and candle data.
|
# Object containing Price and candle data.
|
||||||
self.candles = candles
|
self.candles = candles
|
||||||
# List of all available indicator types
|
|
||||||
# todo: get rid of this use inheritance in classes instead.
|
|
||||||
self.indicator_types = {'simple_indicators': ['RSI', 'SMA', 'EMA', 'LREG'],
|
|
||||||
'other': ['Volume', 'BOLBands', 'MACD', 'ATR']}
|
|
||||||
|
|
||||||
# List of all available indicators
|
# A reference to a dictionary of indicators and properties.
|
||||||
|
# This is updated when a new indicator is created, so it's state should save.
|
||||||
self.indicator_list = config.indicator_list
|
self.indicator_list = config.indicator_list
|
||||||
|
# Dictionary of indicators objects
|
||||||
|
self.indicators = {}
|
||||||
|
# This fill above two dicts
|
||||||
|
self.create_loaded_indicators()
|
||||||
|
|
||||||
|
# Create a List of all available indicator types
|
||||||
|
self.indicator_types = [ ]
|
||||||
|
for i in self.indicator_list:
|
||||||
|
if self.indicator_list[i]['type'] in self.indicator_types:
|
||||||
|
continue
|
||||||
|
self.indicator_types.append(self.indicator_list[i]['type'])
|
||||||
|
|
||||||
# A list of values to use with bolenger bands
|
# A list of values to use with bolenger bands
|
||||||
self.bb_ma_val = {'SMA': 0, 'EMA': 1, 'WMA': 2, 'DEMA': 3, 'TEMA': 4, 'TRIMA': 5, 'KAMA': 6, 'MAMA': 7, 'T3': 8}
|
self.bb_ma_val = {'SMA': 0, 'EMA': 1, 'WMA': 2, 'DEMA': 3, 'TEMA': 4, 'TRIMA': 5, 'KAMA': 6, 'MAMA': 7, 'T3': 8}
|
||||||
|
|
||||||
|
def create_loaded_indicators(self):
|
||||||
|
for each in self.indicator_list:
|
||||||
|
self.create_indicator(each, self.indicator_list[each]['type'], self.indicator_list[each])
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_indicator_defaults():
|
def get_indicator_defaults():
|
||||||
"""Set the default settings for each indicator"""
|
"""Set the default settings for each indicator"""
|
||||||
|
|
@ -58,12 +367,17 @@ class Indicators:
|
||||||
enabled_indicators.append(indctr)
|
enabled_indicators.append(indctr)
|
||||||
return enabled_indicators
|
return enabled_indicators
|
||||||
|
|
||||||
def get_indicator_data(self, symbol=None, interval=None, num_results=100):
|
def get_indicator_data(self, symbol=None, interval=None, num_results=800):
|
||||||
# Loop through all the indicators. If enabled, run the appropriate
|
# Loop through all the indicators. If enabled, run the appropriate
|
||||||
# update function. Return all the results as a dictionary object.
|
# update function. Return all the results as a dictionary object.
|
||||||
|
if symbol is not None:
|
||||||
|
print(symbol)
|
||||||
|
print('get_indicator_data() no symbol implementation')
|
||||||
|
if interval is not None:
|
||||||
|
print(interval)
|
||||||
|
print('get_indicator_data() no interval implementation')
|
||||||
# Get a list of indicator objects and a list of enabled indicators names.
|
# Get a list of indicator objects and a list of enabled indicators names.
|
||||||
i_list = self.get_indicator_list()
|
i_list = self.indicators
|
||||||
enabled_i = self.get_enabled_indicators()
|
enabled_i = self.get_enabled_indicators()
|
||||||
result = {}
|
result = {}
|
||||||
# Loop through all indicator objects in i_list
|
# Loop through all indicator objects in i_list
|
||||||
|
|
@ -71,334 +385,35 @@ class Indicators:
|
||||||
# If the indicator's not enabled skip to next each_i
|
# If the indicator's not enabled skip to next each_i
|
||||||
if each_i not in enabled_i:
|
if each_i not in enabled_i:
|
||||||
continue
|
continue
|
||||||
i_type = i_list[each_i]['type']
|
result[each_i] = i_list[each_i].calculate(self.candles, num_results)
|
||||||
# If it is a simple indicator.
|
|
||||||
if i_type in self.indicator_types['simple_indicators']:
|
|
||||||
result[each_i] = self.calculate_simple_indicator(i_type=i_type,
|
|
||||||
period=i_list[each_i]['period'])
|
|
||||||
if i_type in self.indicator_types['other']:
|
|
||||||
if i_type == 'BOLBands':
|
|
||||||
result[each_i] = self.calculate_bolbands(i_type=i_type,
|
|
||||||
period=i_list[each_i]['period'],
|
|
||||||
devup=i_list[each_i]['devup'],
|
|
||||||
devdn=i_list[each_i]['devdn'],
|
|
||||||
ma=i_list[each_i]['ma'])
|
|
||||||
if i_type == 'MACD':
|
|
||||||
result[each_i] = self.calculate_macd(i_type=i_type,
|
|
||||||
fast_p=i_list[each_i]['fast_p'],
|
|
||||||
slow_p=i_list[each_i]['slow_p'],
|
|
||||||
signal_p=i_list[each_i]['signal_p'])
|
|
||||||
if i_type == 'Volume':
|
|
||||||
result[each_i] = self.candles.get_volume(i_type=i_type)
|
|
||||||
|
|
||||||
if i_type == 'ATR':
|
|
||||||
result[each_i] = self.calculate_atr(i_type=i_type,
|
|
||||||
period=i_list[each_i]['period'])
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def calculate_macd(self, i_type, fast_p=12, slow_p=26, signal_p=9, num_results=800):
|
def delete_indicator(self, indicator):
|
||||||
# These indicators do computations over a period number of price data points.
|
del self.indicator_list[indicator]
|
||||||
# So we need at least that plus what ever amount of results needed.
|
del self.indicators[indicator]
|
||||||
# It seems it needs num_of_nans = (slow_p) - 2) + signal_p
|
|
||||||
|
|
||||||
# TODO: slow_p or fast_p which ever is greater should be used in the calc below.
|
|
||||||
# TODO but i am investigating this.
|
|
||||||
if fast_p > slow_p:
|
|
||||||
raise ValueError('Error I think: TODO: calculate_macd()')
|
|
||||||
num_cv = (slow_p - 2) + signal_p + num_results
|
|
||||||
|
|
||||||
closing_data = self.candles.get_latest_close_values(num_cv)
|
|
||||||
if len(closing_data) < num_cv:
|
|
||||||
print(f'Couldn\'t calculate {i_type} for time period of {slow_p}')
|
|
||||||
print('Not enough data availiable')
|
|
||||||
return
|
|
||||||
# Initialize two arrays to hold a list of closing values and
|
|
||||||
# a list of timestamps associated with these values
|
|
||||||
closes = []
|
|
||||||
ts = []
|
|
||||||
# Isolate all the closing values and timestamps from
|
|
||||||
# the dictionary object
|
|
||||||
for each in closing_data:
|
|
||||||
closes.append(each['close'])
|
|
||||||
ts.append(each['time'])
|
|
||||||
# Convert the list of closes to a numpy array
|
|
||||||
np_real_data = np.array(closes, dtype=float)
|
|
||||||
# Pass the closing values and the period parameter to talib
|
|
||||||
macd, signal, hist = talib.MACD(np_real_data, fast_p, slow_p, signal_p)
|
|
||||||
|
|
||||||
# Combine the new data with the timestamps
|
|
||||||
# Warning: The first (<period> -1) of values are <NAN>.
|
|
||||||
# But they should get trimmed off
|
|
||||||
macd = macd[-num_results:]
|
|
||||||
if len(macd) == 1:
|
|
||||||
print('looks like after slicing')
|
|
||||||
print(macd)
|
|
||||||
signal = signal[-num_results:]
|
|
||||||
hist = hist[-num_results:]
|
|
||||||
ts = ts[-num_results:]
|
|
||||||
r_macd = []
|
|
||||||
r_signal = []
|
|
||||||
r_hist = []
|
|
||||||
for each in range(len(macd)):
|
|
||||||
# filter out nan values
|
|
||||||
if np.isnan(macd[each]):
|
|
||||||
continue
|
|
||||||
r_macd.append({'time': ts[each], 'value': macd[each]})
|
|
||||||
r_signal.append({'time': ts[each], 'value': signal[each]})
|
|
||||||
r_hist.append({'time': ts[each], 'value': hist[each]})
|
|
||||||
r_data = [r_macd, r_signal, r_hist]
|
|
||||||
return {"type": i_type, "data": r_data}
|
|
||||||
|
|
||||||
def calculate_atr(self, i_type, period, num_results=800):
|
|
||||||
# These indicators do computations over period number of price data points.
|
|
||||||
# So we need at least that plus what ever amount of results needed.
|
|
||||||
num_cv = period + num_results
|
|
||||||
|
|
||||||
high_data = self.candles.get_latest_high_values(num_cv)
|
|
||||||
low_data = self.candles.get_latest_low_values(num_cv)
|
|
||||||
close_data = self.candles.get_latest_close_values(num_cv)
|
|
||||||
if len(close_data) < num_cv:
|
|
||||||
print(f'Couldn\'t calculate {i_type} for time period of {period}')
|
|
||||||
print('Not enough data availiable')
|
|
||||||
return
|
|
||||||
# Initialize 4 arrays to hold a list of h/l/c values and
|
|
||||||
# a list of timestamps associated with these values
|
|
||||||
highs = []
|
|
||||||
lows = []
|
|
||||||
closes = []
|
|
||||||
ts = []
|
|
||||||
# Isolate all the values and timestamps from
|
|
||||||
# the dictionary objects
|
|
||||||
|
|
||||||
for each in high_data:
|
|
||||||
highs.append(each['high'])
|
|
||||||
for each in low_data:
|
|
||||||
lows.append(each['low'])
|
|
||||||
for each in close_data:
|
|
||||||
closes.append(each['close'])
|
|
||||||
ts.append(each['time'])
|
|
||||||
# Convert the lists to a numpy array
|
|
||||||
np_highs = np.array(highs, dtype=float)
|
|
||||||
np_lows = np.array(lows, dtype=float)
|
|
||||||
np_closes = np.array(closes, dtype=float)
|
|
||||||
# Pass the closing values and the period parameter to talib
|
|
||||||
atr = talib.ATR(high=np_highs,
|
|
||||||
low=np_lows,
|
|
||||||
close=np_closes,
|
|
||||||
timeperiod=period)
|
|
||||||
# Combine the new data with the timestamps
|
|
||||||
# Warning: The first (<period> -1) of values are <NAN>.
|
|
||||||
# But they should get trimmed off
|
|
||||||
atr = atr[-num_results:]
|
|
||||||
ts = ts[-num_results:]
|
|
||||||
r_data = []
|
|
||||||
for each in range(len(atr)):
|
|
||||||
# filter out nan values
|
|
||||||
if np.isnan(atr[each]):
|
|
||||||
continue
|
|
||||||
r_data.append({'time': ts[each], 'value': atr[each]})
|
|
||||||
return {"type": i_type, "data": r_data}
|
|
||||||
|
|
||||||
def calculate_bolbands(self, i_type, period, devup=2, devdn=2, ma=0, num_results=800):
|
|
||||||
# These indicators do computations over period number of price data points.
|
|
||||||
# So we need at least that plus what ever amount of results needed.
|
|
||||||
# Acceptable values for ma in the talib.BBANDS
|
|
||||||
# {'SMA':0,'EMA':1, 'WMA' : 2, 'DEMA' : 3, 'TEMA' : 4, 'TRIMA' : 5, 'KAMA' : 6, 'MAMA' : 7, 'T3' : 8}
|
|
||||||
num_cv = period + num_results
|
|
||||||
closing_data = self.candles.get_latest_close_values(num_cv)
|
|
||||||
if len(closing_data) < num_cv:
|
|
||||||
print(f'Couldn\'t calculate {i_type} for time period of {period}')
|
|
||||||
print('Not enough data availiable')
|
|
||||||
return
|
|
||||||
# Initialize two arrays to hold a list of closing values and
|
|
||||||
# a list of timestamps associated with these values
|
|
||||||
closes = []
|
|
||||||
ts = []
|
|
||||||
# Isolate all the closing values and timestamps from
|
|
||||||
# the dictionary object
|
|
||||||
for each in closing_data:
|
|
||||||
closes.append(each['close'])
|
|
||||||
ts.append(each['time'])
|
|
||||||
# Convert the list of closes to a numpy array
|
|
||||||
np_real_data = np.array(closes, dtype=float)
|
|
||||||
# Pass the closing values and the period parameter to talib
|
|
||||||
upper, middle, lower = talib.BBANDS(np_real_data,
|
|
||||||
timeperiod=period,
|
|
||||||
# number of non-biased standard deviations from the mean
|
|
||||||
nbdevup=devup,
|
|
||||||
nbdevdn=devdn,
|
|
||||||
# Moving average type: simple moving average here
|
|
||||||
matype=ma)
|
|
||||||
|
|
||||||
# Combine the new data with the timestamps
|
|
||||||
# Warning: The first (<period> -1) of values are <NAN>.
|
|
||||||
# But they should get trimmed off
|
|
||||||
i_values_u = upper[-num_results:]
|
|
||||||
i_values_m = middle[-num_results:]
|
|
||||||
i_values_l = lower[-num_results:]
|
|
||||||
ts = ts[-num_results:]
|
|
||||||
r_data_u = []
|
|
||||||
r_data_m = []
|
|
||||||
r_data_l = []
|
|
||||||
for each in range(len(i_values_u)):
|
|
||||||
# filter out nan values
|
|
||||||
if np.isnan(i_values_u[each]):
|
|
||||||
continue
|
|
||||||
r_data_u.append({'time': ts[each], 'value': i_values_u[each]})
|
|
||||||
r_data_m.append({'time': ts[each], 'value': i_values_m[each]})
|
|
||||||
r_data_l.append({'time': ts[each], 'value': i_values_l[each]})
|
|
||||||
r_data = [r_data_u, r_data_m, r_data_l]
|
|
||||||
return {"type": i_type, "data": r_data}
|
|
||||||
|
|
||||||
def calculate_simple_indicator(self, i_type, period, num_results=800):
|
|
||||||
# Valid types of indicators for this function
|
|
||||||
if i_type not in self.indicator_types['simple_indicators']:
|
|
||||||
raise ValueError(f'calculate_simple_indicator(): Unknown type: {i_type}')
|
|
||||||
|
|
||||||
# These indicators do computations over period number of price data points.
|
|
||||||
# So we need at least that plus what ever amount of results needed.
|
|
||||||
num_cv = period + num_results
|
|
||||||
closing_data = self.candles.get_latest_close_values(num_cv)
|
|
||||||
if len(closing_data) < num_cv:
|
|
||||||
print(f'Could not calculate {i_type} for time period of {period}')
|
|
||||||
print('Not enough data available')
|
|
||||||
return
|
|
||||||
# Initialize two arrays to hold a list of closing values and
|
|
||||||
# a list of timestamps associated with these values
|
|
||||||
closes = []
|
|
||||||
ts = []
|
|
||||||
# Isolate all the closing values and timestamps from
|
|
||||||
# the dictionary object
|
|
||||||
for each in closing_data:
|
|
||||||
closes.append(each['close'])
|
|
||||||
ts.append(each['time'])
|
|
||||||
# Convert the list of closes to a numpy array
|
|
||||||
np_real_data = np.array(closes, dtype=float)
|
|
||||||
# Pass the closing values and the period parameter to talib
|
|
||||||
i_values = None
|
|
||||||
if i_type == 'SMA':
|
|
||||||
i_values = talib.SMA(np_real_data, period)
|
|
||||||
if i_type == 'RSI':
|
|
||||||
i_values = talib.RSI(np_real_data, period)
|
|
||||||
if i_type == 'EMA':
|
|
||||||
i_values = talib.EMA(np_real_data, period)
|
|
||||||
if i_type == 'LREG':
|
|
||||||
i_values = talib.LINEARREG(np_real_data, period)
|
|
||||||
|
|
||||||
# Combine the new data with the timestamps
|
|
||||||
# Warning: The first <period> of rsi values are <NAN>.
|
|
||||||
# But they should get trimmed off todo get rid of try except *just debuging info
|
|
||||||
try:
|
|
||||||
i_values = i_values[-num_results:]
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(f'error: {i_type} {i_values}')
|
|
||||||
ts = ts[-num_results:]
|
|
||||||
r_data = []
|
|
||||||
for each in range(len(i_values)):
|
|
||||||
r_data.append({'time': ts[each], 'value': i_values[each]})
|
|
||||||
return {"type": i_type, "data": r_data}
|
|
||||||
|
|
||||||
def create_indicator(self, name, itype, properties):
|
def create_indicator(self, name, itype, properties):
|
||||||
# Indicator type checking before adding to a dictionary of properties
|
if itype == 'SMA':
|
||||||
properties['type'] = itype
|
self.indicators[name] = SMA(name, itype, properties)
|
||||||
# Force color and period properties for simple indicators
|
if itype == 'EMA':
|
||||||
if itype in self.indicator_types['simple_indicators']:
|
self.indicators[name] = EMA(name, itype, properties)
|
||||||
if 'color' not in properties:
|
if itype == 'RSI':
|
||||||
properties['color'] = f"#{random.randrange(0x1000000):06x}"
|
self.indicators[name] = RSI(name, itype, properties)
|
||||||
if 'period' not in properties:
|
if itype == 'LREG':
|
||||||
properties['period'] = 20
|
self.indicators[name] = LREG(name, itype, properties)
|
||||||
if itype in self.indicator_types['other']:
|
if itype == 'ATR':
|
||||||
ul_col = f"#{random.randrange(0x1000000):06x}"
|
self.indicators[name] = ATR(name, itype, properties)
|
||||||
if itype == 'BOLBands':
|
if itype == 'BOLBands':
|
||||||
if 'period' not in properties:
|
self.indicators[name] = BolBands(name, itype, properties)
|
||||||
properties['period'] = 50
|
if itype == 'MACD':
|
||||||
if 'color_1' not in properties:
|
self.indicators[name] = MACD(name, itype, properties)
|
||||||
properties['color_1'] = ul_col
|
if itype == 'Volume':
|
||||||
if 'color_2' not in properties:
|
self.indicators[name] = Volume(name, itype, properties)
|
||||||
properties['color_2'] = f"#{random.randrange(0x1000000):06x}"
|
|
||||||
if 'color_3' not in properties:
|
|
||||||
properties['color_3'] = ul_col
|
|
||||||
if 'value1' not in properties:
|
|
||||||
properties['value1'] = 0
|
|
||||||
if 'value2' not in properties:
|
|
||||||
properties['value2'] = 0
|
|
||||||
if 'value3' not in properties:
|
|
||||||
properties['value3'] = 0
|
|
||||||
if 'devup' not in properties:
|
|
||||||
properties['devup'] = 2
|
|
||||||
if 'devdn' not in properties:
|
|
||||||
properties['devdn'] = 2
|
|
||||||
if 'ma' not in properties:
|
|
||||||
properties['ma'] = 1
|
|
||||||
if itype == 'MACD':
|
|
||||||
if 'fast_p' not in properties:
|
|
||||||
properties['fast_p'] = 12
|
|
||||||
if 'slow_p' not in properties:
|
|
||||||
properties['slow_p'] = 26
|
|
||||||
if 'signal_p' not in properties:
|
|
||||||
properties['signal_p'] = 9
|
|
||||||
if 'macd' not in properties:
|
|
||||||
properties['macd'] = 0
|
|
||||||
if 'signal' not in properties:
|
|
||||||
properties['signal'] = 0
|
|
||||||
if 'hist' not in properties:
|
|
||||||
properties['hist'] = 0
|
|
||||||
if 'color_1' not in properties:
|
|
||||||
properties['color_1'] = f"#{random.randrange(0x1000000):06x}"
|
|
||||||
if 'color_2' not in properties:
|
|
||||||
properties['color_2'] = f"#{random.randrange(0x1000000):06x}"
|
|
||||||
if itype == 'ATR':
|
|
||||||
if 'period' not in properties:
|
|
||||||
properties['period'] = 50
|
|
||||||
if 'color' not in properties:
|
|
||||||
properties['color'] = f"#{random.randrange(0x1000000):06x}"
|
|
||||||
|
|
||||||
# Force value and visibility for all indicators
|
if name not in self.indicator_list:
|
||||||
if 'value' not in properties:
|
# If we are loading from file it would already exist in here before creation.
|
||||||
properties['value'] = 0
|
self.indicator_list[name] = properties
|
||||||
if 'visible' not in properties:
|
|
||||||
properties['visible'] = True
|
|
||||||
# Add the dictionary of properties and values to an instance list
|
|
||||||
self.indicator_list[name] = properties
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def update_indicators(self):
|
def update_indicators(self):
|
||||||
enabled_indcrs = self.get_enabled_indicators()
|
return self.get_indicator_data(self, num_results=1)
|
||||||
indcrs_list = self.get_indicator_list()
|
|
||||||
# Updated data is collected in this dictionary object
|
|
||||||
updates = {}
|
|
||||||
# Loop through all enabled indicators
|
|
||||||
for indcr in enabled_indcrs:
|
|
||||||
# Get the type of the indicator being updated
|
|
||||||
i_type = indcrs_list[indcr]['type']
|
|
||||||
# Update the indicator with a function appropriate for its kind
|
|
||||||
# TODO - Check EMA results i see a bit of a sharp turn in the ema line on
|
|
||||||
# the interface side when reloading the page. It smooths out after a full reload.
|
|
||||||
if i_type in self.indicator_types['simple_indicators']:
|
|
||||||
updates[indcr] = self.calculate_simple_indicator(i_type=i_type,
|
|
||||||
period=indcrs_list[indcr]['period'],
|
|
||||||
num_results=1)
|
|
||||||
if i_type == 'BOLBands':
|
|
||||||
updates[indcr] = self.calculate_bolbands(i_type=i_type,
|
|
||||||
period=indcrs_list[indcr]['period'],
|
|
||||||
devup=indcrs_list[indcr]['devup'],
|
|
||||||
devdn=indcrs_list[indcr]['devdn'],
|
|
||||||
ma=indcrs_list[indcr]['ma'],
|
|
||||||
num_results=1)
|
|
||||||
if i_type == 'MACD':
|
|
||||||
updates[indcr] = self.calculate_macd(i_type=i_type,
|
|
||||||
fast_p=indcrs_list[indcr]['fast_p'],
|
|
||||||
slow_p=indcrs_list[indcr]['slow_p'],
|
|
||||||
signal_p=indcrs_list[indcr]['signal_p'],
|
|
||||||
num_results=1)
|
|
||||||
|
|
||||||
if i_type == 'ATR':
|
|
||||||
updates[indcr] = self.calculate_atr(i_type=i_type,
|
|
||||||
period=indcrs_list[indcr]['period'],
|
|
||||||
num_results=1)
|
|
||||||
|
|
||||||
if i_type == 'Volume':
|
|
||||||
updates[indcr] = self.candles.get_volume(i_type=i_type,
|
|
||||||
num_results=1)
|
|
||||||
return updates
|
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,20 @@ class Indicators {
|
||||||
// Used in the Create indicator panel (!)Called from inline html.
|
// Used in the Create indicator panel (!)Called from inline html.
|
||||||
let n = document.getElementById("new_prop_name").value;
|
let n = document.getElementById("new_prop_name").value;
|
||||||
let v = document.getElementById("new_prop_value").value;
|
let v = document.getElementById("new_prop_value").value;
|
||||||
|
// Converts css color name to hex
|
||||||
|
if (n == 'color'){
|
||||||
|
// list of valid css colors
|
||||||
|
let colours = {
|
||||||
|
"aliceblue":"#f0f8ff", "antiquewhite":"#faebd7", "aqua":"#00ffff", "aquamarine":"#7fffd4", "azure":"#f0ffff", "beige":"#f5f5dc", "bisque":"#ffe4c4", "black":"#000000", "blanchedalmond":"#ffebcd", "blue":"#0000ff", "blueviolet":"#8a2be2", "brown":"#a52a2a", "burlywood":"#deb887", "cadetblue":"#5f9ea0", "chartreuse":"#7fff00", "chocolate":"#d2691e", "coral":"#ff7f50", "cornflowerblue":"#6495ed", "cornsilk":"#fff8dc", "crimson":"#dc143c", "cyan":"#00ffff", "darkblue":"#00008b", "darkcyan":"#008b8b", "darkgoldenrod":"#b8860b", "darkgray":"#a9a9a9", "darkgreen":"#006400", "darkkhaki":"#bdb76b", "darkmagenta":"#8b008b", "darkolivegreen":"#556b2f", "darkorange":"#ff8c00", "darkorchid":"#9932cc", "darkred":"#8b0000", "darksalmon":"#e9967a", "darkseagreen":"#8fbc8f", "darkslateblue":"#483d8b", "darkslategray":"#2f4f4f", "darkturquoise":"#00ced1", "darkviolet":"#9400d3", "deeppink":"#ff1493", "deepskyblue":"#00bfff", "dimgray":"#696969", "dodgerblue":"#1e90ff", "firebrick":"#b22222", "floralwhite":"#fffaf0", "forestgreen":"#228b22", "fuchsia":"#ff00ff", "gainsboro":"#dcdcdc", "ghostwhite":"#f8f8ff", "gold":"#ffd700", "goldenrod":"#daa520", "gray":"#808080", "green":"#008000", "greenyellow":"#adff2f",
|
||||||
|
"honeydew":"#f0fff0", "hotpink":"#ff69b4", "indianred ":"#cd5c5c", "indigo":"#4b0082", "ivory":"#fffff0", "khaki":"#f0e68c", "lavender":"#e6e6fa", "lavenderblush":"#fff0f5", "lawngreen":"#7cfc00", "lemonchiffon":"#fffacd", "lightblue":"#add8e6", "lightcoral":"#f08080", "lightcyan":"#e0ffff", "lightgoldenrodyellow":"#fafad2", "lightgrey":"#d3d3d3", "lightgreen":"#90ee90", "lightpink":"#ffb6c1", "lightsalmon":"#ffa07a", "lightseagreen":"#20b2aa", "lightskyblue":"#87cefa", "lightslategray":"#778899", "lightsteelblue":"#b0c4de", "lightyellow":"#ffffe0", "lime":"#00ff00", "limegreen":"#32cd32", "linen":"#faf0e6", "magenta":"#ff00ff", "maroon":"#800000", "mediumaquamarine":"#66cdaa", "mediumblue":"#0000cd", "mediumorchid":"#ba55d3", "mediumpurple":"#9370d8", "mediumseagreen":"#3cb371", "mediumslateblue":"#7b68ee", "mediumspringgreen":"#00fa9a", "mediumturquoise":"#48d1cc", "mediumvioletred":"#c71585", "midnightblue":"#191970", "mintcream":"#f5fffa", "mistyrose":"#ffe4e1", "moccasin":"#ffe4b5", "navajowhite":"#ffdead", "navy":"#000080", "oldlace":"#fdf5e6", "olive":"#808000", "olivedrab":"#6b8e23", "orange":"#ffa500", "orangered":"#ff4500", "orchid":"#da70d6", "palegoldenrod":"#eee8aa",
|
||||||
|
"palegreen":"#98fb98", "paleturquoise":"#afeeee", "palevioletred":"#d87093", "papayawhip":"#ffefd5", "peachpuff":"#ffdab9", "peru":"#cd853f", "pink":"#ffc0cb", "plum":"#dda0dd", "powderblue":"#b0e0e6", "purple":"#800080", "rebeccapurple":"#663399", "red":"#ff0000", "rosybrown":"#bc8f8f", "royalblue":"#4169e1", "saddlebrown":"#8b4513", "salmon":"#fa8072", "sandybrown":"#f4a460", "seagreen":"#2e8b57", "seashell":"#fff5ee", "sienna":"#a0522d", "silver":"#c0c0c0", "skyblue":"#87ceeb", "slateblue":"#6a5acd", "slategray":"#708090", "snow":"#fffafa", "springgreen":"#00ff7f", "steelblue":"#4682b4", "tan":"#d2b48c", "teal":"#008080", "thistle":"#d8bfd8", "tomato":"#ff6347", "turquoise":"#40e0d0", "violet":"#ee82ee", "wheat":"#f5deb3", "white":"#ffffff", "whitesmoke":"#f5f5f5", "yellow":"#ffff00", "yellowgreen":"#9acd32"
|
||||||
|
};
|
||||||
|
// if the value is in the list of colors convert it.
|
||||||
|
if (typeof colours[v.toLowerCase()] != 'undefined')
|
||||||
|
v = colours[v.toLowerCase()];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let p={};
|
let p={};
|
||||||
p[n] = v;
|
p[n] = v;
|
||||||
if (document.getElementById("new_prop_list").innerHTML ==""){
|
if (document.getElementById("new_prop_list").innerHTML ==""){
|
||||||
|
|
|
||||||
|
|
@ -313,10 +313,7 @@
|
||||||
<label class="ietextbox" for="{{indicator}}_{{property}}">{{property}}</label>
|
<label class="ietextbox" for="{{indicator}}_{{property}}">{{property}}</label>
|
||||||
{% if property=='type' %}
|
{% if property=='type' %}
|
||||||
<select class="ietextbox" id="{{indicator}}_{{property}}" name="{{property}}">
|
<select class="ietextbox" id="{{indicator}}_{{property}}" name="{{property}}">
|
||||||
{% for i_type in indicator_types['simple_indicators'] %}
|
{% for i_type in indicator_types %}
|
||||||
<option value="{{i_type}}" {% if indicator_list[indicator][property] == i_type %} selected="selected"{%endif%}>{{i_type}}</option>
|
|
||||||
{% endfor %}
|
|
||||||
{% for i_type in indicator_types['other'] %}
|
|
||||||
<option value="{{i_type}}" {% if indicator_list[indicator][property] == i_type %} selected="selected"{%endif%}>{{i_type}}</option>
|
<option value="{{i_type}}" {% if indicator_list[indicator][property] == i_type %} selected="selected"{%endif%}>{{i_type}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -364,10 +361,7 @@
|
||||||
<label for "newi_name">Indicator Name</label><input type ="text" name="newi_name" value="New Indicator">
|
<label for "newi_name">Indicator Name</label><input type ="text" name="newi_name" value="New Indicator">
|
||||||
<label for "newi_type">Type</label>
|
<label for "newi_type">Type</label>
|
||||||
<select id="newi_type" name="newi_type">
|
<select id="newi_type" name="newi_type">
|
||||||
{% for i_type in indicator_types['simple_indicators'] %}
|
{% for i_type in indicator_types %}
|
||||||
<option value="{{i_type}}">{{i_type}}</option>
|
|
||||||
{% endfor %}
|
|
||||||
{% for i_type in indicator_types['other'] %}
|
|
||||||
<option value="{{i_type}}">{{i_type}}</option>
|
<option value="{{i_type}}">{{i_type}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue