Created
May 4, 2022 11:40
-
-
Save arthurwolf/65aad5ad82a0d20a572be828fb2329d0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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