refactor: Move Predictor into class

master
Mike Bryant 5 years ago
parent 5094cc4a66
commit 725bba5ec9

@ -38,43 +38,14 @@ const PROBABILITY_MATRIX = {
const RATE_MULTIPLIER = 10000; const RATE_MULTIPLIER = 10000;
function intceil(val) { function range_length(range) {
return Math.trunc(val + 0.99999); return range[1] - range[0];
}
function minimum_rate_from_given_and_base(given_price, buy_price) {
return RATE_MULTIPLIER * (given_price - 0.99999) / buy_price;
}
function maximum_rate_from_given_and_base(given_price, buy_price) {
return RATE_MULTIPLIER * (given_price + 0.00001) / buy_price;
}
function rate_range_from_given_and_base(given_price, buy_price) {
return [
minimum_rate_from_given_and_base(given_price, buy_price),
maximum_rate_from_given_and_base(given_price, buy_price)
];
}
function get_price(rate, basePrice) {
return intceil(rate * basePrice / RATE_MULTIPLIER);
}
function* multiply_generator_probability(generator, probability) {
for (const it of generator) {
yield {...it, probability: it.probability * probability};
}
} }
function clamp(x, min, max) { function clamp(x, min, max) {
return Math.min(Math.max(x, min), max); return Math.min(Math.max(x, min), max);
} }
function range_length(range) {
return range[1] - range[0];
}
function range_intersect(range1, range2) { function range_intersect(range1, range2) {
if (range1[0] > range2[1] || range1[1] < range2[0]) { if (range1[0] > range2[1] || range1[1] < range2[0]) {
return null; return null;
@ -89,54 +60,6 @@ function range_intersect_length(range1, range2) {
return range_length(range_intersect(range1, range2)); return range_length(range_intersect(range1, range2));
} }
/*
* This corresponds to the code:
* for (int i = start; i < start + length; i++)
* {
* sellPrices[work++] =
* intceil(randfloat(rate_min / RATE_MULTIPLIER, rate_max / RATE_MULTIPLIER) * basePrice);
* }
*
* Would return the conditional probability given the given_prices, and modify
* the predicted_prices array.
* If the given_prices won't match, returns 0.
*/
function generate_individual_random_price(
given_prices, predicted_prices, start, length, rate_min, rate_max) {
rate_min *= RATE_MULTIPLIER;
rate_max *= RATE_MULTIPLIER;
const buy_price = given_prices[0];
const rate_range = [rate_min, rate_max];
let prob = 1;
for (let i = start; i < start + length; i++) {
let min_pred = get_price(rate_min, buy_price);
let max_pred = get_price(rate_max, buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred - FUDGE_FACTOR || given_prices[i] > max_pred + FUDGE_FACTOR) {
// Given price is out of predicted range, so this is the wrong pattern
return 0;
}
// TODO: How to deal with probability when there's fudge factor?
// Clamp the value to be in range now so the probability won't be totally biased to fudged values.
const real_rate_range =
rate_range_from_given_and_base(clamp(given_prices[i], min_pred, max_pred), buy_price);
prob *= range_intersect_length(rate_range, real_rate_range) /
range_length(rate_range);
min_pred = given_prices[i];
max_pred = given_prices[i];
}
predicted_prices.push({
min: min_pred,
max: max_pred,
});
}
return prob;
}
/* /*
* Probability Density Function of rates. * Probability Density Function of rates.
* Since the PDF is continuous*, we approximate it by a discrete probability function: * Since the PDF is continuous*, we approximate it by a discrete probability function:
@ -274,7 +197,91 @@ class PDF {
} }
} }
/* class Predictor {
constructor(prices, first_buy, previous_pattern) {
this.prices = prices;
this.first_buy = first_buy;
this.previous_pattern = previous_pattern;
}
intceil(val) {
return Math.trunc(val + 0.99999);
}
minimum_rate_from_given_and_base(given_price, buy_price) {
return RATE_MULTIPLIER * (given_price - 0.99999) / buy_price;
}
maximum_rate_from_given_and_base(given_price, buy_price) {
return RATE_MULTIPLIER * (given_price + 0.00001) / buy_price;
}
rate_range_from_given_and_base(given_price, buy_price) {
return [
this.minimum_rate_from_given_and_base(given_price, buy_price),
this.maximum_rate_from_given_and_base(given_price, buy_price)
];
}
get_price(rate, basePrice) {
return this.intceil(rate * basePrice / RATE_MULTIPLIER);
}
* multiply_generator_probability(generator, probability) {
for (const it of generator) {
yield {...it, probability: it.probability * probability};
}
}
/*
* This corresponds to the code:
* for (int i = start; i < start + length; i++)
* {
* sellPrices[work++] =
* intceil(randfloat(rate_min / RATE_MULTIPLIER, rate_max / RATE_MULTIPLIER) * basePrice);
* }
*
* Would return the conditional probability given the given_prices, and modify
* the predicted_prices array.
* If the given_prices won't match, returns 0.
*/
generate_individual_random_price(
given_prices, predicted_prices, start, length, rate_min, rate_max) {
rate_min *= RATE_MULTIPLIER;
rate_max *= RATE_MULTIPLIER;
const buy_price = given_prices[0];
const rate_range = [rate_min, rate_max];
let prob = 1;
for (let i = start; i < start + length; i++) {
let min_pred = this.get_price(rate_min, buy_price);
let max_pred = this.get_price(rate_max, buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred - FUDGE_FACTOR || given_prices[i] > max_pred + FUDGE_FACTOR) {
// Given price is out of predicted range, so this is the wrong pattern
return 0;
}
// TODO: How to deal with probability when there's fudge factor?
// Clamp the value to be in range now so the probability won't be totally biased to fudged values.
const real_rate_range =
this.rate_range_from_given_and_base(clamp(given_prices[i], min_pred, max_pred), buy_price);
prob *= range_intersect_length(rate_range, real_rate_range) /
range_length(rate_range);
min_pred = given_prices[i];
max_pred = given_prices[i];
}
predicted_prices.push({
min: min_pred,
max: max_pred,
});
}
return prob;
}
/*
* This corresponds to the code: * This corresponds to the code:
* rate = randfloat(start_rate_min, start_rate_max); * rate = randfloat(start_rate_min, start_rate_max);
* for (int i = start; i < start + length; i++) * for (int i = start; i < start + length; i++)
@ -287,7 +294,7 @@ class PDF {
* the predicted_prices array. * the predicted_prices array.
* If the given_prices won't match, returns 0. * If the given_prices won't match, returns 0.
*/ */
function generate_decreasing_random_price( generate_decreasing_random_price(
given_prices, predicted_prices, start, length, start_rate_min, given_prices, predicted_prices, start, length, start_rate_min,
start_rate_max, rate_decay_min, rate_decay_max) { start_rate_max, rate_decay_min, rate_decay_max) {
start_rate_min *= RATE_MULTIPLIER; start_rate_min *= RATE_MULTIPLIER;
@ -300,8 +307,8 @@ function generate_decreasing_random_price(
let prob = 1; let prob = 1;
for (let i = start; i < start + length; i++) { for (let i = start; i < start + length; i++) {
let min_pred = get_price(rate_pdf.min_value(), buy_price); let min_pred = this.get_price(rate_pdf.min_value(), buy_price);
let max_pred = get_price(rate_pdf.max_value(), buy_price); let max_pred = this.get_price(rate_pdf.max_value(), buy_price);
if (!isNaN(given_prices[i])) { if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred - FUDGE_FACTOR || given_prices[i] > max_pred + FUDGE_FACTOR) { if (given_prices[i] < min_pred - FUDGE_FACTOR || given_prices[i] > max_pred + FUDGE_FACTOR) {
// Given price is out of predicted range, so this is the wrong pattern // Given price is out of predicted range, so this is the wrong pattern
@ -310,7 +317,7 @@ function generate_decreasing_random_price(
// TODO: How to deal with probability when there's fudge factor? // TODO: How to deal with probability when there's fudge factor?
// Clamp the value to be in range now so the probability won't be totally biased to fudged values. // Clamp the value to be in range now so the probability won't be totally biased to fudged values.
const real_rate_range = const real_rate_range =
rate_range_from_given_and_base(clamp(given_prices[i], min_pred, max_pred), buy_price); this.rate_range_from_given_and_base(clamp(given_prices[i], min_pred, max_pred), buy_price);
prob *= rate_pdf.range_limit(real_rate_range); prob *= rate_pdf.range_limit(real_rate_range);
if (prob == 0) { if (prob == 0) {
return 0; return 0;
@ -327,10 +334,10 @@ function generate_decreasing_random_price(
rate_pdf.decay(rate_decay_min, rate_decay_max); rate_pdf.decay(rate_decay_min, rate_decay_max);
} }
return prob; return prob;
} }
/* /*
* This corresponds to the code: * This corresponds to the code:
* rate = randfloat(rate_min, rate_max); * rate = randfloat(rate_min, rate_max);
* sellPrices[work++] = intceil(randfloat(rate_min, rate) * basePrice) - 1; * sellPrices[work++] = intceil(randfloat(rate_min, rate) * basePrice) - 1;
@ -341,7 +348,7 @@ function generate_decreasing_random_price(
* the predicted_prices array. * the predicted_prices array.
* If the given_prices won't match, returns 0. * If the given_prices won't match, returns 0.
*/ */
function generate_peak_price( generate_peak_price(
given_prices, predicted_prices, start, rate_min, rate_max) { given_prices, predicted_prices, start, rate_min, rate_max) {
rate_min *= RATE_MULTIPLIER; rate_min *= RATE_MULTIPLIER;
rate_max *= RATE_MULTIPLIER; rate_max *= RATE_MULTIPLIER;
@ -354,8 +361,8 @@ function generate_peak_price(
// Prob(middle_price) // Prob(middle_price)
const middle_price = given_prices[start + 1]; const middle_price = given_prices[start + 1];
if (!isNaN(middle_price)) { if (!isNaN(middle_price)) {
const min_pred = get_price(rate_min, buy_price); const min_pred = this.get_price(rate_min, buy_price);
const max_pred = get_price(rate_max, buy_price); const max_pred = this.get_price(rate_max, buy_price);
if (middle_price < min_pred - FUDGE_FACTOR || middle_price > max_pred + FUDGE_FACTOR) { if (middle_price < min_pred - FUDGE_FACTOR || middle_price > max_pred + FUDGE_FACTOR) {
// Given price is out of predicted range, so this is the wrong pattern // Given price is out of predicted range, so this is the wrong pattern
return 0; return 0;
@ -363,7 +370,7 @@ function generate_peak_price(
// TODO: How to deal with probability when there's fudge factor? // TODO: How to deal with probability when there's fudge factor?
// Clamp the value to be in range now so the probability won't be totally biased to fudged values. // Clamp the value to be in range now so the probability won't be totally biased to fudged values.
const real_rate_range = const real_rate_range =
rate_range_from_given_and_base(clamp(middle_price, min_pred, max_pred), buy_price); this.rate_range_from_given_and_base(clamp(middle_price, min_pred, max_pred), buy_price);
prob *= range_intersect_length(rate_range, real_rate_range) / prob *= range_intersect_length(rate_range, real_rate_range) /
range_length(rate_range); range_length(rate_range);
if (prob == 0) { if (prob == 0) {
@ -393,15 +400,15 @@ function generate_peak_price(
if (isNaN(price)) { if (isNaN(price)) {
continue; continue;
} }
const min_pred = get_price(rate_min, buy_price) - 1; const min_pred = this.get_price(rate_min, buy_price) - 1;
const max_pred = get_price(rate_range[1], buy_price) - 1; const max_pred = this.get_price(rate_range[1], buy_price) - 1;
if (price < min_pred - FUDGE_FACTOR || price > max_pred + FUDGE_FACTOR) { if (price < min_pred - FUDGE_FACTOR || price > max_pred + FUDGE_FACTOR) {
// Given price is out of predicted range, so this is the wrong pattern // Given price is out of predicted range, so this is the wrong pattern
return 0; return 0;
} }
// TODO: How to deal with probability when there's fudge factor? // TODO: How to deal with probability when there's fudge factor?
// Clamp the value to be in range now so the probability won't be totally biased to fudged values. // Clamp the value to be in range now so the probability won't be totally biased to fudged values.
const rate2_range = rate_range_from_given_and_base(clamp(price, min_pred, max_pred)+ 1, buy_price); const rate2_range = this.rate_range_from_given_and_base(clamp(price, min_pred, max_pred)+ 1, buy_price);
const F = (t, ZZ) => { const F = (t, ZZ) => {
if (t <= 0) { if (t <= 0) {
return 0; return 0;
@ -424,8 +431,8 @@ function generate_peak_price(
// since forward prediction is more useful here. // since forward prediction is more useful here.
// //
// Main spike 1 // Main spike 1
min_pred = get_price(rate_min, buy_price) - 1; let min_pred = this.get_price(rate_min, buy_price) - 1;
max_pred = get_price(rate_max, buy_price) - 1; let max_pred = this.get_price(rate_max, buy_price) - 1;
if (!isNaN(given_prices[start])) { if (!isNaN(given_prices[start])) {
min_pred = given_prices[start]; min_pred = given_prices[start];
max_pred = given_prices[start]; max_pred = given_prices[start];
@ -437,7 +444,7 @@ function generate_peak_price(
// Main spike 2 // Main spike 2
min_pred = predicted_prices[start].min; min_pred = predicted_prices[start].min;
max_pred = get_price(rate_max, buy_price); max_pred = this.get_price(rate_max, buy_price);
if (!isNaN(given_prices[start + 1])) { if (!isNaN(given_prices[start + 1])) {
min_pred = given_prices[start + 1]; min_pred = given_prices[start + 1];
max_pred = given_prices[start + 1]; max_pred = given_prices[start + 1];
@ -448,7 +455,7 @@ function generate_peak_price(
}); });
// Main spike 3 // Main spike 3
min_pred = get_price(rate_min, buy_price) - 1; min_pred = this.get_price(rate_min, buy_price) - 1;
max_pred = predicted_prices[start + 1].max - 1; max_pred = predicted_prices[start + 1].max - 1;
if (!isNaN(given_prices[start + 2])) { if (!isNaN(given_prices[start + 2])) {
min_pred = given_prices[start + 2]; min_pred = given_prices[start + 2];
@ -460,10 +467,9 @@ function generate_peak_price(
}); });
return prob; return prob;
} }
function* * generate_pattern_0_with_lengths(
generate_pattern_0_with_lengths(
given_prices, high_phase_1_len, dec_phase_1_len, high_phase_2_len, given_prices, high_phase_1_len, dec_phase_1_len, high_phase_2_len,
dec_phase_2_len, high_phase_3_len) { dec_phase_2_len, high_phase_3_len) {
/* /*
@ -516,14 +522,14 @@ function*
let probability = 1; let probability = 1;
// High Phase 1 // High Phase 1
probability *= generate_individual_random_price( probability *= this.generate_individual_random_price(
given_prices, predicted_prices, 2, high_phase_1_len, 0.9, 1.4); given_prices, predicted_prices, 2, high_phase_1_len, 0.9, 1.4);
if (probability == 0) { if (probability == 0) {
return; return;
} }
// Dec Phase 1 // Dec Phase 1
probability *= generate_decreasing_random_price( probability *= this.generate_decreasing_random_price(
given_prices, predicted_prices, 2 + high_phase_1_len, dec_phase_1_len, given_prices, predicted_prices, 2 + high_phase_1_len, dec_phase_1_len,
0.6, 0.8, 0.04, 0.1); 0.6, 0.8, 0.04, 0.1);
if (probability == 0) { if (probability == 0) {
@ -531,14 +537,14 @@ function*
} }
// High Phase 2 // High Phase 2
probability *= generate_individual_random_price(given_prices, predicted_prices, probability *= this.generate_individual_random_price(given_prices, predicted_prices,
2 + high_phase_1_len + dec_phase_1_len, high_phase_2_len, 0.9, 1.4); 2 + high_phase_1_len + dec_phase_1_len, high_phase_2_len, 0.9, 1.4);
if (probability == 0) { if (probability == 0) {
return; return;
} }
// Dec Phase 2 // Dec Phase 2
probability *= generate_decreasing_random_price( probability *= this.generate_decreasing_random_price(
given_prices, predicted_prices, given_prices, predicted_prices,
2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len, 2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len,
dec_phase_2_len, 0.6, 0.8, 0.04, 0.1); dec_phase_2_len, 0.6, 0.8, 0.04, 0.1);
@ -553,7 +559,7 @@ function*
const prev_length = 2 + high_phase_1_len + dec_phase_1_len + const prev_length = 2 + high_phase_1_len + dec_phase_1_len +
high_phase_2_len + dec_phase_2_len; high_phase_2_len + dec_phase_2_len;
probability *= generate_individual_random_price( probability *= this.generate_individual_random_price(
given_prices, predicted_prices, prev_length, 14 - prev_length, 0.9, 1.4); given_prices, predicted_prices, prev_length, 14 - prev_length, 0.9, 1.4);
if (probability == 0) { if (probability == 0) {
return; return;
@ -565,9 +571,9 @@ function*
prices: predicted_prices, prices: predicted_prices,
probability, probability,
}; };
} }
function* generate_pattern_0(given_prices) { * generate_pattern_0(given_prices) {
/* /*
decPhaseLen1 = randbool() ? 3 : 2; decPhaseLen1 = randbool() ? 3 : 2;
decPhaseLen2 = 5 - decPhaseLen1; decPhaseLen2 = 5 - decPhaseLen1;
@ -578,15 +584,15 @@ function* generate_pattern_0(given_prices) {
for (var dec_phase_1_len = 2; dec_phase_1_len < 4; dec_phase_1_len++) { for (var dec_phase_1_len = 2; dec_phase_1_len < 4; dec_phase_1_len++) {
for (var high_phase_1_len = 0; high_phase_1_len < 7; high_phase_1_len++) { for (var high_phase_1_len = 0; high_phase_1_len < 7; high_phase_1_len++) {
for (var high_phase_3_len = 0; high_phase_3_len < (7 - high_phase_1_len - 1 + 1); high_phase_3_len++) { for (var high_phase_3_len = 0; high_phase_3_len < (7 - high_phase_1_len - 1 + 1); high_phase_3_len++) {
yield* multiply_generator_probability( yield* this.multiply_generator_probability(
generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_phase_1_len, 7 - high_phase_1_len - high_phase_3_len, 5 - dec_phase_1_len, high_phase_3_len), this.generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_phase_1_len, 7 - high_phase_1_len - high_phase_3_len, 5 - dec_phase_1_len, high_phase_3_len),
1 / (4 - 2) / 7 / (7 - high_phase_1_len)); 1 / (4 - 2) / 7 / (7 - high_phase_1_len));
} }
} }
} }
} }
function* generate_pattern_1_with_peak(given_prices, peak_start) { * generate_pattern_1_with_peak(given_prices, peak_start) {
/* /*
// PATTERN 1: decreasing middle, high spike, random low // PATTERN 1: decreasing middle, high spike, random low
peakStart = randint(3, 9); peakStart = randint(3, 9);
@ -621,17 +627,17 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) {
]; ];
let probability = 1; let probability = 1;
probability *= generate_decreasing_random_price( probability *= this.generate_decreasing_random_price(
given_prices, predicted_prices, 2, peak_start - 2, 0.85, 0.9, 0.03, 0.05); given_prices, predicted_prices, 2, peak_start - 2, 0.85, 0.9, 0.03, 0.05);
if (probability == 0) { if (probability == 0) {
return; return;
} }
// Now each day is independent of next // Now each day is independent of next
min_randoms = [0.9, 1.4, 2.0, 1.4, 0.9, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4] let min_randoms = [0.9, 1.4, 2.0, 1.4, 0.9, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]
max_randoms = [1.4, 2.0, 6.0, 2.0, 1.4, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9] let max_randoms = [1.4, 2.0, 6.0, 2.0, 1.4, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]
for (let i = peak_start; i < 14; i++) { for (let i = peak_start; i < 14; i++) {
probability *= generate_individual_random_price( probability *= this.generate_individual_random_price(
given_prices, predicted_prices, i, 1, min_randoms[i - peak_start], given_prices, predicted_prices, i, 1, min_randoms[i - peak_start],
max_randoms[i - peak_start]); max_randoms[i - peak_start]);
if (probability == 0) { if (probability == 0) {
@ -644,15 +650,15 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) {
prices: predicted_prices, prices: predicted_prices,
probability, probability,
}; };
} }
function* generate_pattern_1(given_prices) { * generate_pattern_1(given_prices) {
for (var peak_start = 3; peak_start < 10; peak_start++) { for (var peak_start = 3; peak_start < 10; peak_start++) {
yield* multiply_generator_probability(generate_pattern_1_with_peak(given_prices, peak_start), 1 / (10 - 3)); yield* this.multiply_generator_probability(this.generate_pattern_1_with_peak(given_prices, peak_start), 1 / (10 - 3));
}
} }
}
function* generate_pattern_2(given_prices) { * generate_pattern_2(given_prices) {
/* /*
// PATTERN 2: consistently decreasing // PATTERN 2: consistently decreasing
rate = 0.9; rate = 0.9;
@ -679,7 +685,7 @@ function* generate_pattern_2(given_prices) {
]; ];
let probability = 1; let probability = 1;
probability *= generate_decreasing_random_price( probability *= this.generate_decreasing_random_price(
given_prices, predicted_prices, 2, 14 - 2, 0.85, 0.9, 0.03, 0.05); given_prices, predicted_prices, 2, 14 - 2, 0.85, 0.9, 0.03, 0.05);
if (probability == 0) { if (probability == 0) {
return; return;
@ -691,9 +697,9 @@ function* generate_pattern_2(given_prices) {
prices: predicted_prices, prices: predicted_prices,
probability, probability,
}; };
} }
function* generate_pattern_3_with_peak(given_prices, peak_start) { * generate_pattern_3_with_peak(given_prices, peak_start) {
/* /*
// PATTERN 3: decreasing, spike, decreasing // PATTERN 3: decreasing, spike, decreasing
@ -738,27 +744,27 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
]; ];
let probability = 1; let probability = 1;
probability *= generate_decreasing_random_price( probability *= this.generate_decreasing_random_price(
given_prices, predicted_prices, 2, peak_start - 2, 0.4, 0.9, 0.03, 0.05); given_prices, predicted_prices, 2, peak_start - 2, 0.4, 0.9, 0.03, 0.05);
if (probability == 0) { if (probability == 0) {
return; return;
} }
// The peak // The peak
probability *= generate_individual_random_price( probability *= this.generate_individual_random_price(
given_prices, predicted_prices, peak_start, 2, 0.9, 1.4); given_prices, predicted_prices, peak_start, 2, 0.9, 1.4);
if (probability == 0) { if (probability == 0) {
return; return;
} }
probability *= generate_peak_price( probability *= this.generate_peak_price(
given_prices, predicted_prices, peak_start + 2, 1.4, 2.0); given_prices, predicted_prices, peak_start + 2, 1.4, 2.0);
if (probability == 0) { if (probability == 0) {
return; return;
} }
if (peak_start + 5 < 14) { if (peak_start + 5 < 14) {
probability *= generate_decreasing_random_price( probability *= this.generate_decreasing_random_price(
given_prices, predicted_prices, peak_start + 5, 14 - (peak_start + 5), given_prices, predicted_prices, peak_start + 5, 14 - (peak_start + 5),
0.4, 0.9, 0.03, 0.05); 0.4, 0.9, 0.03, 0.05);
if (probability == 0) { if (probability == 0) {
@ -772,51 +778,54 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
prices: predicted_prices, prices: predicted_prices,
probability, probability,
}; };
} }
function* generate_pattern_3(given_prices) { * generate_pattern_3(given_prices) {
for (let peak_start = 2; peak_start < 10; peak_start++) { for (let peak_start = 2; peak_start < 10; peak_start++) {
yield* multiply_generator_probability(generate_pattern_3_with_peak(given_prices, peak_start), 1 / (10 - 2)); yield* this.multiply_generator_probability(this.generate_pattern_3_with_peak(given_prices, peak_start), 1 / (10 - 2));
}
} }
}
function get_transition_probability(previous_pattern) { get_transition_probability(previous_pattern) {
if (typeof previous_pattern === 'undefined' || Number.isNaN(previous_pattern) || previous_pattern === null || previous_pattern < 0 || previous_pattern > 3) { if (typeof previous_pattern === 'undefined' || Number.isNaN(previous_pattern) || previous_pattern === null || previous_pattern < 0 || previous_pattern > 3) {
// TODO: Fill the steady state pattern (https://github.com/mikebryant/ac-nh-turnip-prices/pull/90) here. // TODO: Fill the steady state pattern (https://github.com/mikebryant/ac-nh-turnip-prices/pull/90) here.
return [0.346278, 0.247363, 0.147607, 0.258752]; return [0.346278, 0.247363, 0.147607, 0.258752];
} }
return PROBABILITY_MATRIX[previous_pattern]; return PROBABILITY_MATRIX[previous_pattern];
} }
function* generate_all_patterns(sell_prices, previous_pattern) { * generate_all_patterns(sell_prices, previous_pattern) {
const generate_pattern_fns = [generate_pattern_0, generate_pattern_1, generate_pattern_2, generate_pattern_3]; const generate_pattern_fns = [this.generate_pattern_0, this.generate_pattern_1, this.generate_pattern_2, this.generate_pattern_3];
const transition_probability = get_transition_probability(previous_pattern); const transition_probability = this.get_transition_probability(previous_pattern);
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
yield* multiply_generator_probability(generate_pattern_fns[i](sell_prices), transition_probability[i]); yield* this.multiply_generator_probability(generate_pattern_fns[i].bind(this)(sell_prices), transition_probability[i]);
}
} }
}
function* generate_possibilities(sell_prices, first_buy, previous_pattern) { * generate_possibilities(sell_prices, first_buy, previous_pattern) {
if (first_buy || isNaN(sell_prices[0])) { if (first_buy || isNaN(sell_prices[0])) {
for (var buy_price = 90; buy_price <= 110; buy_price++) { for (var buy_price = 90; buy_price <= 110; buy_price++) {
sell_prices[0] = sell_prices[1] = buy_price; sell_prices[0] = sell_prices[1] = buy_price;
if (first_buy) { if (first_buy) {
yield* generate_pattern_3(sell_prices); yield* this.generate_pattern_3(sell_prices);
} else { } else {
// All buy prices are equal probability and we're at the outmost layer, // All buy prices are equal probability and we're at the outmost layer,
// so don't need to multiply_generator_probability here. // so don't need to multiply_generator_probability here.
yield* generate_all_patterns(sell_prices, previous_pattern) yield* this.generate_all_patterns(sell_prices, previous_pattern)
} }
} }
} else { } else {
yield* generate_all_patterns(sell_prices, previous_pattern) yield* this.generate_all_patterns(sell_prices, previous_pattern)
}
} }
}
function analyze_possibilities(sell_prices, first_buy, previous_pattern) { analyze_possibilities() {
const generated_possibilities = Array.from(generate_possibilities(sell_prices, first_buy, previous_pattern)); const sell_prices = this.prices;
const first_buy = this.first_buy;
const previous_pattern = this.previous_pattern;
const generated_possibilities = Array.from(this.generate_possibilities(sell_prices, first_buy, previous_pattern));
console.log(generated_possibilities); console.log(generated_possibilities);
const total_probability = generated_possibilities.reduce((acc, it) => acc + it.probability, 0); const total_probability = generated_possibilities.reduce((acc, it) => acc + it.probability, 0);
@ -846,7 +855,7 @@ function analyze_possibilities(sell_prices, first_buy, previous_pattern) {
poss.weekMax = Math.max(...weekMaxes); poss.weekMax = Math.max(...weekMaxes);
} }
category_totals = {} let category_totals = {}
for (let i of [0, 1, 2, 3]) { for (let i of [0, 1, 2, 3]) {
category_totals[i] = generated_possibilities category_totals[i] = generated_possibilities
.filter(value => value.pattern_number == i) .filter(value => value.pattern_number == i)
@ -862,7 +871,7 @@ function analyze_possibilities(sell_prices, first_buy, previous_pattern) {
return b.category_total_probability - a.category_total_probability || b.probability - a.probability; return b.category_total_probability - a.category_total_probability || b.probability - a.probability;
}); });
global_min_max = []; let global_min_max = [];
for (var day = 0; day < 14; day++) { for (var day = 0; day < 14; day++) {
prices = { prices = {
min: 999, min: 999,
@ -888,4 +897,5 @@ function analyze_possibilities(sell_prices, first_buy, previous_pattern) {
}); });
return generated_possibilities; return generated_possibilities;
}
} }

@ -255,7 +255,8 @@ const calculateOutput = function (data, first_buy, previous_pattern) {
return; return;
} }
let output_possibilities = ""; let output_possibilities = "";
let analyzed_possibilities = analyze_possibilities(data, first_buy, previous_pattern); let predictor = new Predictor(data, first_buy, previous_pattern);
let analyzed_possibilities = predictor.analyze_possibilities();
previous_pattern_number = "" previous_pattern_number = ""
for (let poss of analyzed_possibilities) { for (let poss of analyzed_possibilities) {
var out_line = "<tr><td class='table-pattern'>" + poss.pattern_description + "</td>" var out_line = "<tr><td class='table-pattern'>" + poss.pattern_description + "</td>"

Loading…
Cancel
Save