Classes implemented in python and javascript. UML class diagram. Rough sequence uml. TODO: local file getting dirty from refresh. Signals implemented. Strategies implemented. Ready for implementation of Trades class.
This commit is contained in:
parent
5f5f34c945
commit
5d942a9c2c
|
|
@ -28,20 +28,28 @@ class Configuration:
|
||||||
# Call a static method from indicators that fills in a default list of indicators in config.
|
# Call a static method from indicators that fills in a default list of indicators in config.
|
||||||
self.signals_list = Signals.get_signals_defaults()
|
self.signals_list = Signals.get_signals_defaults()
|
||||||
|
|
||||||
|
# list of strategies in config.
|
||||||
|
self.strategies_list = []
|
||||||
|
|
||||||
# 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 new_strategy(self, data):
|
||||||
|
# The strategies_list is modified by reference in strategies the loaded in config_and_states('save').
|
||||||
|
# Save it to file.
|
||||||
|
self.config_and_states('save')
|
||||||
|
|
||||||
def new_signal(self, data):
|
def new_signal(self, data):
|
||||||
# Create a new signal.
|
# Create a new signal.
|
||||||
self.saved_data['signals'].append(data)
|
self.saved_data['signals'].append(data)
|
||||||
# Save it to file.
|
# Save it to file.
|
||||||
self.config_and_states('save')
|
self.config_and_states('save')
|
||||||
|
|
||||||
def remove_signal(self, data):
|
def remove(self, what, name):
|
||||||
print(f'removing {data}')
|
print(f'removing {what}:{name}')
|
||||||
for sig in self.saved_data['signals']:
|
for obj in self.saved_data[what]:
|
||||||
if sig['name'] == data:
|
if obj['name'] == name:
|
||||||
self.saved_data['signals'].remove(sig)
|
self.saved_data[what].remove(obj)
|
||||||
break
|
break
|
||||||
# Save it to file.
|
# Save it to file.
|
||||||
self.config_and_states('save')
|
self.config_and_states('save')
|
||||||
|
|
@ -53,7 +61,8 @@ class Configuration:
|
||||||
self.saved_data = {
|
self.saved_data = {
|
||||||
'indicator_list': self.indicator_list,
|
'indicator_list': self.indicator_list,
|
||||||
'config': {'chart_interval': self.chart_interval, 'trading_pair': self.trading_pair},
|
'config': {'chart_interval': self.chart_interval, 'trading_pair': self.trading_pair},
|
||||||
'signals': self.signals_list
|
'signals': self.signals_list,
|
||||||
|
'strategies': self.strategies_list
|
||||||
}
|
}
|
||||||
|
|
||||||
def set_loaded_values():
|
def set_loaded_values():
|
||||||
|
|
@ -62,6 +71,7 @@ class Configuration:
|
||||||
self.chart_interval = self.saved_data['config']['chart_interval']
|
self.chart_interval = self.saved_data['config']['chart_interval']
|
||||||
self.trading_pair = self.saved_data['config']['trading_pair']
|
self.trading_pair = self.saved_data['config']['trading_pair']
|
||||||
self.signals_list = self.saved_data['signals']
|
self.signals_list = self.saved_data['signals']
|
||||||
|
self.strategies_list = self.saved_data['strategies']
|
||||||
|
|
||||||
def load_configuration(filepath):
|
def load_configuration(filepath):
|
||||||
"""load file data"""
|
"""load file data"""
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class Signal:
|
||||||
class Signals:
|
class Signals:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.signals = []
|
self.signals = []
|
||||||
self.set_signals_defaults()
|
# self.set_signals_defaults()
|
||||||
|
|
||||||
def set_signals_defaults(self):
|
def set_signals_defaults(self):
|
||||||
"""These defaults are loaded if the config file is not found."""
|
"""These defaults are loaded if the config file is not found."""
|
||||||
|
|
@ -91,7 +91,6 @@ class Signals:
|
||||||
prop1=sig['prop1'], operator=sig['operator'],
|
prop1=sig['prop1'], operator=sig['operator'],
|
||||||
source2=sig['source2'], prop2=sig['prop2'],
|
source2=sig['source2'], prop2=sig['prop2'],
|
||||||
state=sig['state']))
|
state=sig['state']))
|
||||||
print(self.signals)
|
|
||||||
|
|
||||||
def get_signals(self):
|
def get_signals(self):
|
||||||
return self.signals
|
return self.signals
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
class Strategies:
|
||||||
|
def __init__(self, loaded_strats):
|
||||||
|
self.strat_list = loaded_strats
|
||||||
|
|
||||||
|
def new_strategy(self, data):
|
||||||
|
self.strat_list.append(data)
|
||||||
|
|
||||||
|
def delete_strategy(self, name):
|
||||||
|
for obj in self.strat_list:
|
||||||
|
if obj['name'] == name:
|
||||||
|
self.strat_list.remove(obj)
|
||||||
|
break
|
||||||
|
|
||||||
|
def get_strategies(self):
|
||||||
|
return self.strat_list
|
||||||
24
app.py
24
app.py
|
|
@ -61,6 +61,15 @@ def ws(sock):
|
||||||
}
|
}
|
||||||
resp = json.dumps(resp)
|
resp = json.dumps(resp)
|
||||||
sock.send(resp)
|
sock.send(resp)
|
||||||
|
elif msg_obj['data'] == 'strategies':
|
||||||
|
strategies = bt.app_data.get_strategies()
|
||||||
|
if strategies:
|
||||||
|
resp = {
|
||||||
|
"reply": "strategies",
|
||||||
|
"data": strategies
|
||||||
|
}
|
||||||
|
resp = json.dumps(resp)
|
||||||
|
sock.send(resp)
|
||||||
else:
|
else:
|
||||||
print('Warning: Unhandled request!')
|
print('Warning: Unhandled request!')
|
||||||
print(msg_obj['data'])
|
print(msg_obj['data'])
|
||||||
|
|
@ -68,6 +77,9 @@ def ws(sock):
|
||||||
if msg_obj['message_type'] == 'delete_signal':
|
if msg_obj['message_type'] == 'delete_signal':
|
||||||
bt.app_data.delete_signal(msg_obj['data'])
|
bt.app_data.delete_signal(msg_obj['data'])
|
||||||
|
|
||||||
|
if msg_obj['message_type'] == 'delete_strategy':
|
||||||
|
bt.app_data.delete_strategy(msg_obj['data'])
|
||||||
|
|
||||||
if msg_obj['message_type'] == 'reply':
|
if msg_obj['message_type'] == 'reply':
|
||||||
print(msg_obj['rep'])
|
print(msg_obj['rep'])
|
||||||
print('Reply')
|
print('Reply')
|
||||||
|
|
@ -83,6 +95,18 @@ def ws(sock):
|
||||||
}
|
}
|
||||||
resp = json.dumps(resp)
|
resp = json.dumps(resp)
|
||||||
sock.send(resp)
|
sock.send(resp)
|
||||||
|
|
||||||
|
if msg_obj['message_type'] == 'new_strategy':
|
||||||
|
# Send the data to the BrighterData_obj
|
||||||
|
# and forward any returned data to the client.
|
||||||
|
r_data = bt.app_data.received_new_strategy(msg_obj['data'])
|
||||||
|
if r_data:
|
||||||
|
resp = {
|
||||||
|
"reply": "strategy_created",
|
||||||
|
"data": r_data
|
||||||
|
}
|
||||||
|
resp = json.dumps(resp)
|
||||||
|
sock.send(resp)
|
||||||
return
|
return
|
||||||
|
|
||||||
# The rendered page connects to the exchange and relays the candle data back here
|
# The rendered page connects to the exchange and relays the candle data back here
|
||||||
|
|
|
||||||
32
data.py
32
data.py
|
|
@ -1,6 +1,7 @@
|
||||||
from binance.client import Client
|
from binance.client import Client
|
||||||
|
|
||||||
import config
|
import config
|
||||||
|
from Strategies import Strategies
|
||||||
from candles import Candles
|
from candles import Candles
|
||||||
from Configuration import Configuration
|
from Configuration import Configuration
|
||||||
from exchange_info import ExchangeInfo
|
from exchange_info import ExchangeInfo
|
||||||
|
|
@ -36,6 +37,9 @@ class BrighterData:
|
||||||
# Object that maintains exchange and account data
|
# Object that maintains exchange and account data
|
||||||
self.exchange_info = ExchangeInfo(self.client)
|
self.exchange_info = ExchangeInfo(self.client)
|
||||||
|
|
||||||
|
# Object that maintains the strategies data
|
||||||
|
self.strategies = Strategies(self.config.strategies_list)
|
||||||
|
|
||||||
def get_js_init_data(self):
|
def get_js_init_data(self):
|
||||||
"""Returns a JSON object of initialization data
|
"""Returns a JSON object of initialization data
|
||||||
for the javascript in the rendered HTML"""
|
for the javascript in the rendered HTML"""
|
||||||
|
|
@ -90,8 +94,26 @@ class BrighterData:
|
||||||
self.signals.new_signal(data)
|
self.signals.new_signal(data)
|
||||||
# Forward the new signal data to config. So it can save it to file.
|
# Forward the new signal data to config. So it can save it to file.
|
||||||
self.config.new_signal(data)
|
self.config.new_signal(data)
|
||||||
|
# Send the data back to where it came from.
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def received_new_strategy(self, data):
|
||||||
|
# Check the data.
|
||||||
|
if 'name' not in data:
|
||||||
|
return 'data.py:received_new_strategy() - The new strategy has no name. '
|
||||||
|
# Forward the new strategy data to the strategy's instance. So it can create a new strategy.
|
||||||
|
self.strategies.new_strategy(data)
|
||||||
|
# Forward the new signal data to config. So it can save it to file.
|
||||||
|
self.config.new_strategy(data)
|
||||||
|
# Send the data back to where it came from.
|
||||||
|
return data
|
||||||
|
|
||||||
|
def delete_strategy(self, strategy_name):
|
||||||
|
# Delete the signal from the signals instance.
|
||||||
|
self.strategies.delete_strategy(strategy_name)
|
||||||
|
# Delete the signal from the configuration file.
|
||||||
|
self.config.remove('strategies', strategy_name)
|
||||||
|
|
||||||
def get_signals(self):
|
def get_signals(self):
|
||||||
""" Return a JSON object of all the signals in the signals instance."""
|
""" Return a JSON object of all the signals in the signals instance."""
|
||||||
sigs = self.signals.get_signals()
|
sigs = self.signals.get_signals()
|
||||||
|
|
@ -100,11 +122,19 @@ class BrighterData:
|
||||||
json_str.append(json.dumps(sig.__dict__))
|
json_str.append(json.dumps(sig.__dict__))
|
||||||
return json_str
|
return json_str
|
||||||
|
|
||||||
|
def get_strategies(self):
|
||||||
|
""" Return a JSON object of all the signals in the signals instance."""
|
||||||
|
strats = self.strategies.get_strategies()
|
||||||
|
json_str = []
|
||||||
|
for strat in strats:
|
||||||
|
json_str.append(json.dumps(strat))
|
||||||
|
return json_str
|
||||||
|
|
||||||
def delete_signal(self, signal_name):
|
def delete_signal(self, signal_name):
|
||||||
# Delete the signal from the signals instance.
|
# Delete the signal from the signals instance.
|
||||||
self.signals.delete_signal(signal_name)
|
self.signals.delete_signal(signal_name)
|
||||||
# Delete the signal from the configuration file.
|
# Delete the signal from the configuration file.
|
||||||
self.config.remove_signal(signal_name)
|
self.config.remove('signals', signal_name)
|
||||||
|
|
||||||
|
|
||||||
app_data = BrighterData()
|
app_data = BrighterData()
|
||||||
|
|
|
||||||
|
|
@ -359,13 +359,17 @@ class Indicators:
|
||||||
"""Set the default settings for each indicator"""
|
"""Set the default settings for each indicator"""
|
||||||
|
|
||||||
indicator_list = {
|
indicator_list = {
|
||||||
'SMA 21': {'type': 'SMA', 'period': 21, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
'EMA 5': {'type': 'EMA', 'period': 5, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
|
'value': 0},
|
||||||
|
'EMA 15': {'type': 'EMA', 'period': 15, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
|
'value': 0},
|
||||||
|
'EMA 20': {'type': 'EMA', 'period': 20, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
'value': 0},
|
'value': 0},
|
||||||
'EMA 50': {'type': 'EMA', 'period': 50, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
'EMA 50': {'type': 'EMA', 'period': 50, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
'value': 0},
|
'value': 0},
|
||||||
'EMA 100': {'type': 'EMA', 'period': 100, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
'EMA 100': {'type': 'EMA', 'period': 100, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
'value': 0},
|
'value': 0},
|
||||||
'SMA 200': {'type': 'SMA', 'period': 200, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
'EMA 200': {'type': 'EMA', 'period': 200, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
'value': 0},
|
'value': 0},
|
||||||
'RSI 14': {'type': 'RSI', 'period': 14, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
'RSI 14': {'type': 'RSI', 'period': 14, 'visible': True, 'color': f"#{random.randrange(0x1000000):06x}",
|
||||||
'value': 0},
|
'value': 0},
|
||||||
|
|
|
||||||
|
|
@ -1,86 +1,35 @@
|
||||||
class Strategy{
|
//TODO this func is unused left over for reference.
|
||||||
constructor(strat_type, name, side, take_profit, stop_loss, conditions) {
|
//conditions_satisfied(signals){
|
||||||
// The type of alert.
|
// let result = true;
|
||||||
this.type = strat_type;
|
// for(let cond of this.conditions){
|
||||||
// The source of the alert.
|
// if (cond.trig_val == 'true'){
|
||||||
this.name = name;
|
// if (signals[cond.on] == true){
|
||||||
// buy|sell: string
|
// result = result && true;
|
||||||
this.side = side;
|
// }else{
|
||||||
// Conditions to exit trade in profit. {on: ('profit'|'condition'), trig_val: 999}
|
// result = false;
|
||||||
this.take_profit = take_profit;
|
// }
|
||||||
// Conditions to exit trade in loss. {on: ('loss'|'condition'), trig_val: 999}
|
// }
|
||||||
this.stop_loss = stop_loss;
|
// else if (cond.trig_val == 'false'){
|
||||||
// The conditions to evaluate. { on: (signal_name: str), trig_val: (true|false|changed) }
|
// if (signals[cond.on] == false){
|
||||||
this.conditions = conditions;
|
// result = result && true;
|
||||||
// html formatted representation.
|
// }else{
|
||||||
this.display_output = this.format_html();
|
// result = false;
|
||||||
// any last results needed for comparison.
|
// }
|
||||||
this.last_result = {};
|
// }
|
||||||
}
|
// else if (cond.trig_val == 'changed'){
|
||||||
format_html(){
|
// // If no last result exists for this trigger, create one.
|
||||||
let html ='<li>' + '<span>' + this.name + '</span>';
|
// if ( !this.last_results[cond.on] ){
|
||||||
html +='<span>' + this.type + '</span>';
|
// this.last_results[cond.on] = signals[cond.on];
|
||||||
html +='<span>' + this.side + '</span>';
|
// }
|
||||||
if (this.take_profit.on == 'profit'){
|
// if (signals[cond.on] != this.last_results[cond.on]){
|
||||||
if(this.side == 'buy') {var then_do ='sell';}
|
// result = result && true;
|
||||||
else if(this.side == 'sell') {var then_do ='buy';}
|
// }else{
|
||||||
html += '<span>' + 'If profit exceeds' + ': ' + this.take_profit.trig_val + ' '+ then_do + '.</span>';
|
// result = false;
|
||||||
}
|
// }
|
||||||
if (this.stop_loss.on == 'loss'){
|
// }
|
||||||
if(this.side == 'buy') {var then_do ='sell';}
|
// }
|
||||||
else if(this.side == 'sell') {var then_do ='buy';}
|
// return result;
|
||||||
html +='<span>' + 'If loss exceeds' + ': ' + this.stop_loss.trig_val + ' '+ then_do + '.</span>';
|
//}
|
||||||
}
|
|
||||||
for(let cond of this.conditions){
|
|
||||||
html += '<span>If ' + cond.on + ' is ' + cond.trig_val + '</span>';
|
|
||||||
}
|
|
||||||
html += '</li>';
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
conditions_satisfied(signals){
|
|
||||||
let result = true;
|
|
||||||
for(let cond of this.conditions){
|
|
||||||
if (cond.trig_val == 'true'){
|
|
||||||
if (signals[cond.on] == true){
|
|
||||||
result = result && true;
|
|
||||||
}else{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond.trig_val == 'false'){
|
|
||||||
if (signals[cond.on] == false){
|
|
||||||
result = result && true;
|
|
||||||
}else{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond.trig_val == 'changed'){
|
|
||||||
// If no last result exists for this trigger, create one.
|
|
||||||
if ( !this.last_results[cond.on] ){
|
|
||||||
this.last_results[cond.on] = signals[cond.on];
|
|
||||||
}
|
|
||||||
if (signals[cond.on] != this.last_results[cond.on]){
|
|
||||||
result = result && true;
|
|
||||||
}else{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
name(){
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
type(){
|
|
||||||
return this.type;
|
|
||||||
}
|
|
||||||
strategy(){
|
|
||||||
return this.strategy;
|
|
||||||
}
|
|
||||||
print_html(){
|
|
||||||
return this.display_output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class Strategies {
|
class Strategies {
|
||||||
constructor(target_id) {
|
constructor(target_id) {
|
||||||
// The list of strategies.
|
// The list of strategies.
|
||||||
|
|
@ -95,21 +44,123 @@ class Strategies {
|
||||||
open_form() { document.getElementById("new_strat_form").style.display = "grid"; }
|
open_form() { document.getElementById("new_strat_form").style.display = "grid"; }
|
||||||
// Call to hide Create new signal dialog.
|
// Call to hide Create new signal dialog.
|
||||||
close_form() { document.getElementById("new_strat_form").style.display = "none"; }
|
close_form() { document.getElementById("new_strat_form").style.display = "none"; }
|
||||||
|
submit(){
|
||||||
|
/*
|
||||||
|
- Collect the data from the form fields and
|
||||||
|
create an object representing the strategy.
|
||||||
|
- Record the strategy in the an instance list.
|
||||||
|
- Update the display output.
|
||||||
|
- Send the strategy object to the server.
|
||||||
|
*/
|
||||||
|
let strat = {};
|
||||||
|
strat.name = document.getElementById('stg_name').value;
|
||||||
|
if (strat.name == ''){
|
||||||
|
alert('Please provide a name.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strat.type = document.getElementById('strat_type').value;
|
||||||
|
strat.side = document.getElementById('trade_in_side').value;
|
||||||
|
strat.margin = document.getElementById('margin_select').value;
|
||||||
|
strat.trd_in_conds = {};
|
||||||
|
let conds = Array.from(document.querySelectorAll('#trade_in_cond>li'));
|
||||||
|
for (let cond of conds){
|
||||||
|
let json_obj = JSON.parse(cond.innerHTML);
|
||||||
|
strat.trd_in_conds[json_obj.Trigger] = json_obj.Value;
|
||||||
|
}
|
||||||
|
let take_profit = {};
|
||||||
|
take_profit.typ = document.getElementById('prof_typ').value;
|
||||||
|
if (take_profit.typ == 'conditional'){
|
||||||
|
take_profit.trig = document.getElementById('prof_trig').value;
|
||||||
|
take_profit.val = document.getElementById('prof_trigVal').value;
|
||||||
|
}else{
|
||||||
|
take_profit.val = document.getElementById('prof_val').value;
|
||||||
|
}
|
||||||
|
strat.take_profit = take_profit;
|
||||||
|
let stop_loss = {};
|
||||||
|
stop_loss.typ = document.getElementById('loss_typ').value;
|
||||||
|
if ( stop_loss.typ == 'conditional' ){
|
||||||
|
stop_loss.trig = document.getElementById('loss_trig').value;
|
||||||
|
stop_loss.val = document.getElementById('loss_trigVal').value;
|
||||||
|
}else{
|
||||||
|
stop_loss.val = document.getElementById('loss_val').value;
|
||||||
|
}
|
||||||
|
strat.stop_loss = stop_loss;
|
||||||
|
// Add the strategy to the instance list.
|
||||||
|
this.strategies.push(strat);
|
||||||
|
// Add the strategy to display.
|
||||||
|
this.update_html();
|
||||||
|
// Send the new strategy to the server.
|
||||||
|
window.UI.data.comms.send_to_app( "new_strategy", strat);
|
||||||
|
this.close_form();
|
||||||
|
}
|
||||||
|
set_data(strats){
|
||||||
|
for (let strat of strats){
|
||||||
|
// Add the strategy to the instance list.
|
||||||
|
this.strategies.push(JSON.parse(strat));
|
||||||
|
}
|
||||||
|
// Add the strategy to display.
|
||||||
|
this.update_html();
|
||||||
|
}
|
||||||
open_stg_form(){
|
open_stg_form(){
|
||||||
this.open_form();
|
this.open_form();
|
||||||
this.fill_field('strat_opt', 'take_profit');
|
this.fill_field('strat_opt', 'take_profit');
|
||||||
// condition = { on: (signal_name: str), trig_val: (true|false|changed) }
|
}
|
||||||
let cond1 = {on: 'signal1', trig_val:'changed'}
|
clear_innerHTML(el){
|
||||||
// take_profit = {on: ('profit'|'condition'), trig_val: 999}
|
el.innerHTML="";
|
||||||
let take_profit = {on: 'signal2', trig_val: false}
|
}
|
||||||
// stop_loss = {on: ('loss'|'condition'), trig_val: 999}
|
dropDown(name, label, parent, options){
|
||||||
let stop_loss = {on: 'loss', trig_val: '80%' }
|
/* Create a html selection element and append it to a parent element.
|
||||||
let side='buy';
|
name: name and id of the element.
|
||||||
let conditions = []; //_str = side + condition + take_profit
|
label: text displayed beside the selection list element.
|
||||||
conditions.push(cond1);
|
parent: the html element to append to.
|
||||||
this.strategies.push( new Strategy('take_profit', 'strategy_#1', side, take_profit, stop_loss, conditions) );
|
options: An array of selection options.
|
||||||
this.update_html();
|
*/
|
||||||
|
let lbl = document.createElement("label");
|
||||||
|
lbl.for = name;
|
||||||
|
lbl.id = name + '_lbl';
|
||||||
|
lbl.innerHTML = label;
|
||||||
|
let select = document.createElement("select");
|
||||||
|
select.id = name;
|
||||||
|
select.name = name;
|
||||||
|
for(let option of options){
|
||||||
|
select.innerHTML += '<option>' + option + '</option>';
|
||||||
|
}
|
||||||
|
parent.appendChild(lbl);
|
||||||
|
parent.appendChild(select);
|
||||||
|
}
|
||||||
|
val_input(name, label, parent, min, max, i_val){
|
||||||
|
/* Create an input element.
|
||||||
|
name: name and id of the element.
|
||||||
|
label: text displayed beside the element.
|
||||||
|
parent: the html element to append to.
|
||||||
|
min, max, i_val: Range and initialization values.
|
||||||
|
*/
|
||||||
|
let lbl = document.createElement("label");
|
||||||
|
lbl.for = name;
|
||||||
|
lbl.id = name + '_lbl';
|
||||||
|
lbl.innerHTML = label;
|
||||||
|
let input = document.createElement("input");
|
||||||
|
input.name = name;
|
||||||
|
input.id = name;
|
||||||
|
input.type = 'number';
|
||||||
|
input.min = min;
|
||||||
|
input.max = max;
|
||||||
|
input.value = i_val;
|
||||||
|
parent.appendChild(lbl);
|
||||||
|
parent.appendChild(input);
|
||||||
|
|
||||||
|
}
|
||||||
|
hideShowTags(elements, cmd){
|
||||||
|
/* Hides or shows 1 or many elements.
|
||||||
|
Receives either string or array of string.
|
||||||
|
*/
|
||||||
|
if (typeof(elements) == 'string'){
|
||||||
|
elements = [elements];
|
||||||
|
}
|
||||||
|
for(let el of elements){
|
||||||
|
if(cmd== 'hide'){document.getElementById(el).style.display = 'none';}
|
||||||
|
if(cmd== 'show'){document.getElementById(el).style.display = 'inline-block';}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fill_field(field, value){
|
fill_field(field, value){
|
||||||
if (field == 'strat_opt'){
|
if (field == 'strat_opt'){
|
||||||
|
|
@ -117,35 +168,17 @@ class Strategies {
|
||||||
|
|
||||||
if (value == 'take_profit'){
|
if (value == 'take_profit'){
|
||||||
// Clear previous content.
|
// Clear previous content.
|
||||||
options.innerHTML="";
|
this.clear_innerHTML(options);
|
||||||
|
|
||||||
//Create a drop down for buy/sell option
|
//Create a drop down for buy/sell option
|
||||||
let side_select_label = document.createElement("label");
|
this.dropDown('trade_in_side','Side:', options, ['buy','sell']);
|
||||||
side_select_label.for = 'trade_in_side';
|
|
||||||
side_select_label.innerHTML = 'Side:';
|
|
||||||
let side_select = document.createElement("select");
|
|
||||||
side_select.id = "trade_in_side";
|
|
||||||
side_select.name = "trade_in_side";
|
|
||||||
side_select.innerHTML = '<option>buy</option><option>sell</option>';
|
|
||||||
options.appendChild(side_select_label);
|
|
||||||
options.appendChild(side_select);
|
|
||||||
|
|
||||||
//Create an input for margin trading value. (1X-100X)
|
//Create an input for margin trading value. (1-100)
|
||||||
let margin_label = document.createElement("label");
|
this.val_input('margin_select', 'Margin:', options, 1,100, 50);
|
||||||
margin_label.for = 'margin';
|
|
||||||
margin_label.innerHTML = 'Margin:';
|
|
||||||
let margin_select = document.createElement("input");
|
|
||||||
margin_select.name = 'margin';
|
|
||||||
margin_select.type = 'number';
|
|
||||||
margin_select.min = 1;
|
|
||||||
margin_select.max = 100;
|
|
||||||
margin_select.value = 1;
|
|
||||||
options.appendChild(margin_label);
|
|
||||||
options.appendChild(margin_select);
|
|
||||||
|
|
||||||
// Create a un ordered list to hold the conditions of trading in.
|
// Create a un ordered list to hold the conditions of trading in.
|
||||||
let ul_in_cond = document.createElement('ul');
|
let ul_in_cond = document.createElement('ul');
|
||||||
ul_in_cond.id ='trade_in_conditions';
|
ul_in_cond.id ='trade_in_cond';
|
||||||
|
|
||||||
// Create a submit button for the conditions.
|
// Create a submit button for the conditions.
|
||||||
let add_cond_btn = document.createElement('button');
|
let add_cond_btn = document.createElement('button');
|
||||||
|
|
@ -154,116 +187,108 @@ class Strategies {
|
||||||
add_cond_btn.innerHTML = "Add Condition";
|
add_cond_btn.innerHTML = "Add Condition";
|
||||||
add_cond_btn.onclick = function () {
|
add_cond_btn.onclick = function () {
|
||||||
let li = document.createElement('li');
|
let li = document.createElement('li');
|
||||||
li.innerHTML = 'Trigger:'+ trigger.value+' Value:' + trigVal.value;
|
li.innerHTML = JSON.stringify({ Trigger: trigger.value, Value: trigVal.value });
|
||||||
ul_in_cond.appendChild(li);
|
ul_in_cond.appendChild(li);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add a horizontal rule.
|
// Add a horizontal rule.
|
||||||
let element = document.createElement('hr');
|
options.appendChild(document.createElement('hr'));
|
||||||
options.appendChild(element);
|
|
||||||
|
|
||||||
//Create a drop down for trigger options
|
//Create a drop down for trigger options
|
||||||
let trigger_label = document.createElement("label");
|
// Get the signal options from the signal instance.
|
||||||
trigger_label.for = 'trigger';
|
let ops = [];
|
||||||
trigger_label.innerHTML = 'Trigger Signal:';
|
for (let signal of window.UI.signals.signals) {ops.push(signal.name);}
|
||||||
let trigger = document.createElement("select");
|
this.dropDown('trigger','Trigger Signal:', options, ops);
|
||||||
trigger.id = "trigger";
|
|
||||||
trigger.name = "trigger";
|
|
||||||
// Populate the signal selector.
|
|
||||||
for (let signal in window.UI.signals.signals){
|
|
||||||
let opt = document.createElement('option');
|
|
||||||
opt.value = window.UI.signals.signals[signal].name;
|
|
||||||
opt.innerHTML = window.UI.signals.signals[signal].name;
|
|
||||||
trigger.appendChild(opt);
|
|
||||||
}
|
|
||||||
// Add it to the dom.
|
|
||||||
options.appendChild(trigger_label);
|
|
||||||
options.appendChild(trigger);
|
|
||||||
|
|
||||||
//Create a drop down for trigger value.
|
//Create a drop down for trigger value.
|
||||||
let trigVal_label = document.createElement("label");
|
this.dropDown('trigVal','Trigger Value:', options, ['true', 'false', 'changed']);
|
||||||
trigVal_label.for = 'trigVal';
|
|
||||||
trigVal_label.innerHTML = 'Trigger Value:';
|
|
||||||
let trigVal = document.createElement("select");
|
|
||||||
trigVal.id = "trigVal";
|
|
||||||
trigVal.name = "trigVal";
|
|
||||||
|
|
||||||
let opt = document.createElement('option');
|
|
||||||
opt.value = true;
|
|
||||||
opt.innerHTML = 'true';
|
|
||||||
trigVal.appendChild(opt);
|
|
||||||
|
|
||||||
opt = document.createElement('option');
|
|
||||||
opt.value = false;
|
|
||||||
opt.innerHTML = 'false';
|
|
||||||
trigVal.appendChild(opt);
|
|
||||||
|
|
||||||
opt = document.createElement('option');
|
|
||||||
opt.value = 'changed';
|
|
||||||
opt.innerHTML = 'changed';
|
|
||||||
trigVal.appendChild(opt);
|
|
||||||
|
|
||||||
// Add trigger Value select element to the dom.
|
|
||||||
options.appendChild(trigVal_label);
|
|
||||||
options.appendChild(trigVal);
|
|
||||||
|
|
||||||
// Add the submit btn and the list to the dom.
|
// Add the submit btn and the list to the dom.
|
||||||
options.appendChild(add_cond_btn);
|
options.appendChild(add_cond_btn);
|
||||||
options.appendChild(ul_in_cond);
|
options.appendChild(ul_in_cond);
|
||||||
|
|
||||||
// Add a horizontal rule.
|
// Add a horizontal rule.
|
||||||
element = document.createElement('hr');
|
options.appendChild(document.createElement('hr'));
|
||||||
options.appendChild(element);
|
|
||||||
|
|
||||||
//Create an input for take profit value.
|
|
||||||
let prof_value_lbl = document.createElement("label");
|
|
||||||
prof_value_lbl.for = 'profit_val';
|
|
||||||
prof_value_lbl.innerHTML = 'Profit %:';
|
|
||||||
let profit_val = document.createElement("input");
|
|
||||||
profit_val.type='number';
|
|
||||||
profit_val.min=0; profit_val.max=100; profit_val.value = 50;
|
|
||||||
|
|
||||||
//Create a drop down for take profit type.
|
//Create a drop down for take profit type.
|
||||||
let prof_typ_label = document.createElement("label");
|
this.dropDown('prof_typ','Profit type:', options, ['value', 'conditional']);
|
||||||
prof_typ_label.for = 'prof_typ';
|
// Add and onchange function to show and hide some options.
|
||||||
prof_typ_label.innerHTML = 'Profit type:';
|
let that = this;
|
||||||
let prof_typ = document.createElement("select");
|
document.getElementById('prof_typ').onchange= function(){
|
||||||
prof_typ.id = "prof_typ";
|
|
||||||
prof_typ.name = "prof_typ";
|
|
||||||
prof_typ.onchange= function(){
|
|
||||||
if (this.value == 'value'){
|
if (this.value == 'value'){
|
||||||
prof_value_lbl.style.display = 'inline-block';
|
that.hideShowTags(['prof_val_lbl','prof_val'], 'show');
|
||||||
profit_val.style.display = 'inline-block';
|
that.hideShowTags(['prof_trig_lbl', 'prof_trig', 'prof_trigVal_lbl', 'prof_trigVal'], 'hide');
|
||||||
//profit_trig.style.display = 'none';
|
|
||||||
}
|
}
|
||||||
else if (this.value == 'conditional'){
|
else if (this.value == 'conditional'){
|
||||||
prof_value_lbl.style.display = 'none';
|
that.hideShowTags(['prof_val_lbl','prof_val'], 'hide');
|
||||||
profit_val.style.display = 'none';
|
that.hideShowTags(['prof_trig_lbl', 'prof_trig', 'prof_trigVal_lbl', 'prof_trigVal'], 'show');
|
||||||
//profit_trig.style.display = 'block';
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
opt = document.createElement('option');
|
// Add a line break.
|
||||||
opt.value = 'value';
|
options.appendChild(document.createElement('br'));
|
||||||
opt.innerHTML = 'value';
|
|
||||||
prof_typ.appendChild(opt);
|
|
||||||
|
|
||||||
opt = document.createElement('option');
|
// Create an input for take profit value.
|
||||||
opt.value = 'conditional';
|
this.val_input('prof_val', 'Profit %:', options, 1,100, 50);
|
||||||
opt.innerHTML = 'conditional';
|
// Set display to visible.
|
||||||
prof_typ.appendChild(opt);
|
this.hideShowTags(['prof_val_lbl','prof_val'], 'show');
|
||||||
|
|
||||||
// Add profit_type select element to the dom.
|
// Create an input for take profit signal trigger.
|
||||||
options.appendChild(prof_typ_label);
|
// Get the signal options from the signal instance.
|
||||||
options.appendChild(prof_typ);
|
ops = []; for (let signal of window.UI.signals.signals) {ops.push(signal.name);}
|
||||||
|
this.dropDown('prof_trig','Profit trigger:', options, ops);
|
||||||
|
// Set display to hidden.
|
||||||
|
this.hideShowTags(['prof_trig_lbl','prof_trig'], 'hide');
|
||||||
|
|
||||||
opt = document.createElement('br');
|
//Create a drop down for take profit trigger value.
|
||||||
options.appendChild(opt);
|
this.dropDown('prof_trigVal','Trigger Value:', options, ['true', 'false', 'changed']);
|
||||||
|
// Set display to hidden.
|
||||||
|
this.hideShowTags(['prof_trigVal_lbl','prof_trigVal'], 'hide');
|
||||||
|
|
||||||
// Add value input to the dom.
|
// Add a line break.
|
||||||
options.appendChild(prof_value_lbl);
|
options.appendChild(document.createElement('br'));
|
||||||
options.appendChild(profit_val);
|
// Add a horizontal rule.
|
||||||
|
options.appendChild(document.createElement('hr'));
|
||||||
|
|
||||||
|
//Create a drop down for Stop Loss type.
|
||||||
|
this.dropDown('loss_typ','Stop-Loss type:', options, ['value', 'conditional']);
|
||||||
|
// Add and onchange function to show and hide some options.
|
||||||
|
document.getElementById('loss_typ').onchange= function(){
|
||||||
|
if (this.value == 'value'){
|
||||||
|
that.hideShowTags(['loss_val_lbl','loss_val'], 'show');
|
||||||
|
that.hideShowTags(['loss_trig_lbl', 'loss_trig', 'loss_trigVal_lbl', 'loss_trigVal'], 'hide');
|
||||||
|
}
|
||||||
|
else if (this.value == 'conditional'){
|
||||||
|
that.hideShowTags(['loss_val_lbl','loss_val'], 'hide');
|
||||||
|
that.hideShowTags(['loss_trig_lbl', 'loss_trig', 'loss_trigVal_lbl', 'loss_trigVal'], 'show');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a line break.
|
||||||
|
options.appendChild( document.createElement('br') );
|
||||||
|
|
||||||
|
// Create an input for take profit value.
|
||||||
|
this.val_input('loss_val', 'Loss %:', options, 1,100, 50);
|
||||||
|
// Set display to visible.
|
||||||
|
this.hideShowTags(['loss_val_lbl','loss_val'], 'show');
|
||||||
|
|
||||||
|
// Create an input for take profit signal trigger.
|
||||||
|
// Get the signal options from the signal instance.
|
||||||
|
ops = []; for (let signal of window.UI.signals.signals) {ops.push(signal.name);}
|
||||||
|
this.dropDown('loss_trig','Stop-Loss trigger:', options, ops);
|
||||||
|
// Set display to hidden.
|
||||||
|
this.hideShowTags(['loss_trig_lbl','loss_trig'], 'hide');
|
||||||
|
|
||||||
|
//Create a drop down for take profit trigger value.
|
||||||
|
this.dropDown('loss_trigVal','Loss Value:', options, ['true', 'false', 'changed']);
|
||||||
|
// Set display to hidden.
|
||||||
|
this.hideShowTags(['loss_trigVal_lbl','loss_trigVal'], 'hide');
|
||||||
|
|
||||||
|
// Add a line break.
|
||||||
|
options.appendChild(document.createElement('br'));
|
||||||
|
// Add a horizontal rule.
|
||||||
|
options.appendChild(document.createElement('hr'));
|
||||||
|
|
||||||
}
|
}
|
||||||
if (value == 'incremental_profits'){
|
if (value == 'incremental_profits'){
|
||||||
|
|
@ -274,14 +299,25 @@ class Strategies {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set_target(){
|
initialize(){
|
||||||
// This is called after the html document has been parsed.
|
// This is called after the html document has been parsed.
|
||||||
this.target = document.getElementById(this.target_id);
|
this.target = document.getElementById(this.target_id);
|
||||||
|
// Send a request to the server for any loaded data.
|
||||||
|
window.UI.data.comms.send_to_app('request', 'strategies');
|
||||||
|
}
|
||||||
|
del(name){
|
||||||
|
window.UI.data.comms.send_to_app('delete_strategy', name);
|
||||||
|
// Get the child element node
|
||||||
|
let child = document.getElementById(name + '_item');
|
||||||
|
// Remove the child element from the document
|
||||||
|
child.parentNode.removeChild(child);
|
||||||
}
|
}
|
||||||
update_html(){
|
update_html(){
|
||||||
let strats ='';
|
let strats ='';
|
||||||
|
let on_click = " window.UI.strats.del(this.value);";
|
||||||
for (let strat of this.strategies){
|
for (let strat of this.strategies){
|
||||||
strats += strat.print_html();
|
let button ="<button type='button' name='delete' class='e_btn' value='" + strat.name + "' onclick='" + on_click + "'>✘</button>";
|
||||||
|
strats += "<li id='" + strat.name + "_item'>" + button + "<pre>" + JSON.stringify(strat) + "</pre></li>";
|
||||||
}
|
}
|
||||||
this.target.innerHTML = strats;
|
this.target.innerHTML = strats;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ class Comms {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
send_to_app(message_type, data){
|
send_to_app(message_type, data){
|
||||||
|
console.log('window.UI.data.comms.send_to_app(): Sending->');
|
||||||
console.log( JSON.stringify({ message_type: message_type, data : data }));
|
console.log( JSON.stringify({ message_type: message_type, data : data }));
|
||||||
if (this.connection_open){
|
if (this.connection_open){
|
||||||
this.app_con.send( JSON.stringify({ message_type: message_type, data : data }));
|
this.app_con.send( JSON.stringify({ message_type: message_type, data : data }));
|
||||||
|
|
@ -83,6 +84,10 @@ class Comms {
|
||||||
/* On initialization the server will send a list of signals loaded from file.
|
/* On initialization the server will send a list of signals loaded from file.
|
||||||
Forward this to the signals instance.*/
|
Forward this to the signals instance.*/
|
||||||
window.UI.signals.set_data(msg.data);
|
window.UI.signals.set_data(msg.data);
|
||||||
|
}else if (msg.reply == 'strategies'){
|
||||||
|
/* On initialization the server will send a list of strategies loaded from file.
|
||||||
|
Forward this to the strategies instance.*/
|
||||||
|
window.UI.strats.set_data(msg.data);
|
||||||
}
|
}
|
||||||
else if (msg.reply =='signal_created'){
|
else if (msg.reply =='signal_created'){
|
||||||
/* After the server creates a new signal it will send the details here.
|
/* After the server creates a new signal it will send the details here.
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,8 @@ class User_Interface{
|
||||||
window.UI.signals.request_signals();
|
window.UI.signals.request_signals();
|
||||||
// initialize the alerts instance.
|
// initialize the alerts instance.
|
||||||
window.UI.alerts.set_target();
|
window.UI.alerts.set_target();
|
||||||
// initialize the alerts instance.
|
// initialize the strategies instance.
|
||||||
window.UI.strats.set_target();
|
window.UI.strats.initialize();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ class Signals {
|
||||||
// Keep a local record of the signals.
|
// Keep a local record of the signals.
|
||||||
this.signals.push(obj);
|
this.signals.push(obj);
|
||||||
// Define the function that is called when deleting an individual signal.
|
// Define the function that is called when deleting an individual signal.
|
||||||
let click_func = "window.UI.signals.delete_signal('" + obj.name+ "')";
|
let click_func = "window.UI.signals.delete_signal('" + obj.name + "')";
|
||||||
// create a delete button for every individual signal.
|
// create a delete button for every individual signal.
|
||||||
let delete_btn = "<button onclick='" + click_func + "' style='color:red;'>✘</button>";
|
let delete_btn = '<button onclick="' + click_func + '" style="color:red;">✘</button>';
|
||||||
|
|
||||||
// Put all the attributes into html elements.
|
// Put all the attributes into html elements.
|
||||||
let signal_name = " <span>" + obj.name + ": </span>";
|
let signal_name = " <span>" + obj.name + ": </span>";
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
<div id="strat_opt"></div>
|
<div id="strat_opt"></div>
|
||||||
<div style="grid-column: 1 / span 2; grid-row: 5;">
|
<div style="grid-column: 1 / span 2; grid-row: 5;">
|
||||||
<button type="button" class="btn cancel" onclick="UI.strats.close_form()">Close</button>
|
<button type="button" class="btn cancel" onclick="UI.strats.close_form()">Close</button>
|
||||||
<button type="button" class="btn next" onclick="UI.strats.next(1)">Next</button>
|
<button type="button" class="btn next" onclick="UI.strats.submit()">Create Strategy</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!----End panel 1--------->
|
</div><!----End panel 1--------->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue