Skip to content

Instantly share code, notes, and snippets.

@arthurwolf
Created May 4, 2022 11:40
Show Gist options
  • Save arthurwolf/65aad5ad82a0d20a572be828fb2329d0 to your computer and use it in GitHub Desktop.
Save arthurwolf/65aad5ad82a0d20a572be828fb2329d0 to your computer and use it in GitHub Desktop.
// Sort the results from best to worst
sort(results){
// Skip and limit
let limit = new Number(this.sort_limit);
let skip = new Number(this.sort_skip);
if(skip > limit) skip = limit;
// Fix negative lows
results = results = results.map(r => {r.low = Math.max(0, r.low); return r;});
// Create new factors
results = results.map(r => {return { ...r, 'range': r.high/r.low }});
results = results.map(r => {return { ...r, 'minmax': r.max/r.min }});
results = results.map(r => {return { ...r, 'trades': r.total_trades }});
results = results.map(r => {return { ...r, 'progress': r.last_price/r.start_price }});
results = results.map(r => {return { ...r, 'exit': ((r.max-r.min)/(r.last_price-r.min)) }});
// Fix NaN/Infinite values
results = results = results.map(r => {r.range = !isFinite(r.range) ? 0 : r.range; return r;});
results = results = results.map(r => {r.minmax = !isFinite(r.minmax) ? 0 : r.minmax; return r;});
results = results = results.map(r => {r.progress = !isFinite(r.progress) ? 0 : r.progress; return r;});
// Normalize
// TODO: Make a composite based on this
// TODO: range isn't a parameter, make it. Same for minmax and progress. Then no need for the switch.
let normalize = (parameter) => {
let min = Math.min(...results.map(o => o[parameter]));
let max = Math.max(...results.map(o => o[parameter]), 0);
for(let result of results) result[`normalized_${parameter}`] = (result[parameter]-min)/(max-min);
};
for(let parameter of "exit currency buy_hold range total_trades trades".split(" ")) normalize(parameter);
// Create cumulative factors
for(let result of results){
result.cumulative_buy_hold = ((this.cumulative_buy_hold[result.selector] || 0) * this.thinner) + result.normalized_buy_hold;
result.cumulative_trades = ((this.cumulative_trades[ result.selector] || 0) * this.thinner) + result.normalized_trades;
result.cumulative_range = ((this.cumulative_range[ result.selector] || 0) * this.thinner) + result.normalized_range;
this.cumulative_buy_hold[result.selector] = result.cumulative_buy_hold;
this.cumulative_trades[ result.selector] = result.cumulative_trades;
this.cumulative_range[ result.selector] = result.cumulative_range;
}
// Averaging
for(let result of results){
// Log buy_hold
if(!this.history_of.buy_hold[result.selector]) this.history_of.buy_hold[result.selector] = [];
this.history_of.buy_hold[result.selector].push(result.buy_hold);
// Log normalized_buy_hold
if(!this.history_of.buy_hold[result.selector]) this.history_of.buy_hold[result.selector] = [];
this.history_of.buy_hold[result.selector].push(result.buy_hold);
// If we have enough history, average, otherwise use the latest value
if(this.history_of.buy_hold[result.selector] > this.sort_averaging + 1){
// Get the averaged value
let rounded_sort_averaging = Math.floor(this.sort_averaging);
let total = 0;
if(rounded_sort_averaging > 0){
let end = [...this.history_of.buy_hold[result.selector].slice(0-rounded_sort_averaging)];
total = end.reduce((partial_sum, a) => partial_sum + a, 0);
}
let remainder = this.sort_averaging - rounded_sort_averaging;
let remaining = this.history_of.buy_hold[result.selector][this.history_of.buy_hold[result.selector].length-1-rounded_sort_averaging];
if(remainder != 0) total += (remaining*remainder);
result.averaged_buy_hold = total / this.sort_averaging;
}else{
result.averaged_buy_hold = result.buy_hold;
}
}
// Create composite factors
results = results.map(r => {return { ...r, 'multwo': (1+r.normalized_buy_hold)*(1+r.normalized_range) }});
results = results.map(r => {return { ...r, 'multhree': (1+r.normalized_buy_hold)*(1+r.normalized_range)*(1+r.normalized_total_trades) }});
results = results.map(r => {return { ...r, 'mulfive': (1+r.normalized_buy_hold)*(1+r.normalized_range)*(1+r.normalized_total_trades)*(1+r.normalized_exit)*(1+r.normalized_currency) }});
results = results.map(r => {return { ...r, 'plustwo': r.normalized_buy_hold+r.normalized_range }});
results = results.map(r => {return { ...r, 'plusthree': r.normalized_buy_hold+r.normalized_range+r.normalized_total_trades }});
results = results.map(r => {return { ...r, 'plusfive': r.normalized_buy_hold+r.normalized_range+r.normalized_total_trades+r.normalized_exit+r.normalized_currency }});
// Limiting through minima and maxima
if(this.min_buy_hold) results = results.filter(r => r.buy_hold >= this.min_buy_hold);
if(this.max_buy_hold) results = results.filter(r => r.buy_hold <= this.max_buy_hold);
// If we need to offset, prepare the offset here
// TODO: This currently works only for periods of 1
let skip_offset = this.skip_change ? (parseFloat(this.skip_change) * (this.current_period/365)) : 0;
let limit_offset = this.limit_change ? (parseFloat(this.limit_change) * (this.current_period/365)) : 0;
// If the limit/skips are a factor. We do this at the end because we might change the length of it before we get here.
if(/\./.test(this.sort_limit)) limit = Math.round((limit+limit_offset) * results.length);
if(/\./.test(this.sort_skip )) skip = Math.round((skip +skip_offset ) * results.length);
// Actually sort
return [skip, limit, results.sort((a, b) => b[this.sort_factor] - a[this.sort_factor])];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment