brighter-trading/static/Strategies.js

363 lines
15 KiB
JavaScript

class Strategies {
constructor(target_id) {
// The list of strategies.
this.strategies = [];
// The html element id that displays the strategies.
this.target_id = target_id;
// The html element that displays the the strategies.
this.target = null;
}
// Call to display Create new signal dialog.
open_form() { document.getElementById("new_strat_form").style.display = "grid"; }
// Call to hide Create new signal dialog.
close_form() { document.getElementById("new_strat_form").style.display = "none"; }
submit(){
/*
- Collect the data from the form fields and
create a json object representing a strategy.
- Append the strategy to a local list of strategies.
- Update the display output.
- Send the strategy info to the server.
*/
let strat = {};
strat.name = document.getElementById('stg_name').value;
if (strat.name == ''){
alert('Please provide a name.');
return;
}
// The type of strategy will determine underlying feature of its execution.
strat.type = document.getElementById('strat_type').value;
// Whether the strategy is bullish or bearish.
strat.side = document.getElementById('trade_in_side').value;
// Position size for each trade the strategy executes.
strat.trade_amount = document.getElementById('trade_amount').value;
// The maximum combined position allowed.
strat.max_position = document.getElementById('strgy_total').value;
// The fee the exchange charges per trade.
strat.trading_fee = document.getElementById('fee').value;
// The maximum allowable loss the strategy can endure in combined trades.
// Before trading out and terminating execution.
strat.max_loss = document.getElementById('max_loss').value;
// The trading pair being exchanged.
strat.symbol = window.UI.data.trading_pair;
// The combined profit or loss including trading fees.
strat.net_pl = 0;
// The combined profit or loss.
strat.gross_pl = 0;
// The quantity of the traded assets being held.
strat.combined_position = 0;
// Opening value of the asset.
strat.opening_value = 0;
// The current value of the asset.
strat.current_value = 0;
// Whether or not the strategy has begun trading.
strat.active = false;
// The conditions that must be met before trading in.
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;
}
// The conditions that must be met before taking profit.
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;
// The conditions that must be met before taking a loss.
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.sendToApp( "new_strategy", strat);
// Close the html form.
this.close_form();
}
update_received(stg_updts){
if ( 'cmd' in stg_updts) {
let alert =
window.UI.alerts.publish_alerts('strategy', stg_updts);
this.executeCmd(stg_updts.cmd);
}
console.log('recieved stategy update.');
console.log(stg_updts);
}
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(){
this.open_form();
this.fill_field('strat_opt', 'in-out');
}
clear_innerHTML(el){
el.innerHTML="";
}
dropDown(name, label, parent, options){
/* Create a html selection element and append it to a parent element.
name: name and id of the element.
label: text displayed beside the selection list element.
parent: the html element to append to.
options: An array of selection options.
*/
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, style = null){
/* 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;
if (max) {input.max = max;}
input.value = i_val;
if (style){
input.style = style;
}
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){
if (field == 'strat_opt'){
let options = document.getElementById('strat_opt');
if (value == 'in-out'){
// Clear previous content.
this.clear_innerHTML(options);
// Add a horizontal rule.
options.appendChild(document.createElement('hr'));
//Create a drop down for buy/sell option
this.dropDown('trade_in_side','Side:', options, ['buy','sell']);
//Create an input for the margin. (1-100)
this.val_input('margin_select', 'Margin:', options, 1,100, 50);
// Add a line break.
options.appendChild( document.createElement('br') );
//Create an input for the amount. (1-*)
this.val_input('trade_amount', 'Trade amount:', options, 1, 0, 1,'width: 54px;');
//Create an input for the amount. (1-*)
this.val_input('strgy_total', 'Strategy total:', options, 1, 0, 10, 'width: 54px;');
// Add a line break.
options.appendChild( document.createElement('br') );
//Create an input for the fee. (0.01-1)
this.val_input('fee', 'Trading Fee:', options, 0.001, 1, 0.025);
// Create a un ordered list to hold the conditions of trading in.
let ul_in_cond = document.createElement('ul');
ul_in_cond.id ='trade_in_cond';
// Create a submit button for the conditions.
let add_cond_btn = document.createElement('button');
add_cond_btn.setAttribute('id','add_cond_btn');
add_cond_btn.setAttribute('type','button');
add_cond_btn.innerHTML = "Add Condition";
add_cond_btn.onclick = function () {
let li = document.createElement('li');
li.innerHTML = JSON.stringify({ Trigger: trigger.value, Value: trigVal.value });
ul_in_cond.appendChild(li);
};
// Add a horizontal rule.
options.appendChild(document.createElement('hr'));
//Create a drop down for trigger options
// Get the signal options from the signal instance.
let ops = [];
for (let signal of window.UI.signals.signals) {ops.push(signal.name);}
this.dropDown('trigger','Trigger Signal:', options, ops);
//Create a drop down for trigger value.
this.dropDown('trigVal','Trigger Value:', options, ['true', 'false', 'changed']);
// Add the submit btn and the list to the dom.
options.appendChild(add_cond_btn);
options.appendChild(ul_in_cond);
// Add a horizontal rule.
options.appendChild(document.createElement('hr'));
//Create a drop down for take profit type.
this.dropDown('prof_typ','Profit type:', options, ['value', 'conditional']);
// Add and onchange function to show and hide some options.
let that = this;
document.getElementById('prof_typ').onchange= function(){
if (this.value == 'value'){
that.hideShowTags(['prof_val_lbl','prof_val'], 'show');
that.hideShowTags(['prof_trig_lbl', 'prof_trig', 'prof_trigVal_lbl', 'prof_trigVal'], 'hide');
}
else if (this.value == 'conditional'){
that.hideShowTags(['prof_val_lbl','prof_val'], 'hide');
that.hideShowTags(['prof_trig_lbl', 'prof_trig', 'prof_trigVal_lbl', 'prof_trigVal'], 'show');
}
};
// Add a line break.
options.appendChild(document.createElement('br'));
// Create an input for take profit value.
this.val_input('prof_val', 'Profit %:', options, 1,100, 50);
// Set display to visible.
this.hideShowTags(['prof_val_lbl','prof_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('prof_trig','Profit trigger:', options, ops);
// Set display to hidden.
this.hideShowTags(['prof_trig_lbl','prof_trig'], 'hide');
//Create a drop down for take profit trigger value.
this.dropDown('prof_trigVal','Trigger Value:', options, ['true', 'false', 'changed']);
// Set display to hidden.
this.hideShowTags(['prof_trigVal_lbl','prof_trigVal'], 'hide');
// Add a line break.
options.appendChild(document.createElement('br'));
// Add a horizontal rule.
options.appendChild(document.createElement('hr'));
// Create an input for tolerable loss.
this.val_input('max_loss', 'Max loss :', options, 1,100, 50);
// Add a line break.
options.appendChild(document.createElement('br'));
//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 stop loss 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'){
options.innerHTML="Incremental_profits -> not done.";
}
if (value == 'swing'){
options.innerHTML="swing -> not done.";
}
}
}
initialize(){
// This is called after the html document has been parsed.
this.target = document.getElementById(this.target_id);
// Send a request to the server for any loaded data.
window.UI.data.comms.sendToApp('request', 'strategies');
}
del(name){
window.UI.data.comms.sendToApp('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(){
let strats ='';
let on_click = " window.UI.strats.del(this.value);";
for (let strat of this.strategies){
let button ="<button type='button' name='delete' class='e_btn' value='" + strat.name + "' onclick='" + on_click + "'>&#10008;</button>";
strats += "<li id='" + strat.name + "_item'>" + button + "<pre>" + JSON.stringify(strat) + "</pre></li>";
}
this.target.innerHTML = strats;
}
}