|
|
|
@ -1,3 +1,7 @@
|
|
|
|
|
// The reverse-engineered code is not perfectly accurate, especially as it's not
|
|
|
|
|
// 32-bit ARM floating point. So, be tolerant of slightly unexpected inputs
|
|
|
|
|
const FUDGE_FACTOR = 5;
|
|
|
|
|
|
|
|
|
|
const PATTERN = {
|
|
|
|
|
FLUCTUATING: 0,
|
|
|
|
|
LARGE_SPIKE: 1,
|
|
|
|
@ -10,7 +14,7 @@ const PATTERN_COUNTS = {
|
|
|
|
|
[PATTERN.LARGE_SPIKE]: 7,
|
|
|
|
|
[PATTERN.DECREASING]: 1,
|
|
|
|
|
[PATTERN.SMALL_SPIKE]: 8,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const PROBABILITY_MATRIX = {
|
|
|
|
|
[PATTERN.FLUCTUATING]: {
|
|
|
|
@ -39,15 +43,187 @@ const PROBABILITY_MATRIX = {
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const RATE_MULTIPLIER = 10000;
|
|
|
|
|
|
|
|
|
|
function intceil(val) {
|
|
|
|
|
return Math.trunc(val + 0.99999);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function minimum_rate_from_given_and_base(given_price, buy_price) {
|
|
|
|
|
return 10000 * (given_price - 1) / buy_price;
|
|
|
|
|
return RATE_MULTIPLIER * (given_price - 0.99999) / buy_price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function maximum_rate_from_given_and_base(given_price, buy_price) {
|
|
|
|
|
return 10000 * given_price / buy_price;
|
|
|
|
|
return RATE_MULTIPLIER * (given_price + 0.00001) / buy_price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function get_price(rate, basePrice) {
|
|
|
|
|
return intceil(rate * basePrice / RATE_MULTIPLIER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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 modify the predicted_prices array.
|
|
|
|
|
* If the given_prices won't match, returns false, otherwise returns true
|
|
|
|
|
*/
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
|
|
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 false;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This corresponds to the code:
|
|
|
|
|
* rate = randfloat(start_rate_min, start_rate_max);
|
|
|
|
|
* for (int i = start; i < start + length; i++)
|
|
|
|
|
* {
|
|
|
|
|
* sellPrices[work++] = intceil(rate * basePrice);
|
|
|
|
|
* rate -= randfloat(rate_decay_min, rate_decay_max);
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* Would modify the predicted_prices array.
|
|
|
|
|
* If the given_prices won't match, returns false, otherwise returns true
|
|
|
|
|
*/
|
|
|
|
|
function generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices, start, length, rate_min,
|
|
|
|
|
rate_max, rate_decay_min, rate_decay_max) {
|
|
|
|
|
rate_min *= RATE_MULTIPLIER;
|
|
|
|
|
rate_max *= RATE_MULTIPLIER;
|
|
|
|
|
rate_decay_min *= RATE_MULTIPLIER;
|
|
|
|
|
rate_decay_max *= RATE_MULTIPLIER;
|
|
|
|
|
|
|
|
|
|
const buy_price = given_prices[0];
|
|
|
|
|
|
|
|
|
|
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 false;
|
|
|
|
|
}
|
|
|
|
|
if (given_prices[i] >= min_pred || given_prices[i] <= max_pred) {
|
|
|
|
|
// The value in the FUDGE_FACTOR range is ignored so the rate range would not be empty.
|
|
|
|
|
const real_rate_min = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
const real_rate_max = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
rate_min = Math.max(rate_min, real_rate_min);
|
|
|
|
|
rate_max = Math.min(rate_max, real_rate_max);
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
rate_min -= rate_decay_max;
|
|
|
|
|
rate_max -= rate_decay_min;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This corresponds to the code:
|
|
|
|
|
* rate = randfloat(rate_min, rate_max);
|
|
|
|
|
* sellPrices[work++] = intceil(randfloat(rate_min, rate) * basePrice) - 1;
|
|
|
|
|
* sellPrices[work++] = intceil(rate * basePrice);
|
|
|
|
|
* sellPrices[work++] = intceil(randfloat(rate_min, rate) * basePrice) - 1;
|
|
|
|
|
*
|
|
|
|
|
* Would modify the predicted_prices array.
|
|
|
|
|
* If the given_prices won't match, returns false, otherwise returns true
|
|
|
|
|
*/
|
|
|
|
|
function generate_peak_price(
|
|
|
|
|
given_prices, predicted_prices, start, rate_min, rate_max) {
|
|
|
|
|
rate_min *= RATE_MULTIPLIER;
|
|
|
|
|
rate_max *= RATE_MULTIPLIER;
|
|
|
|
|
|
|
|
|
|
const buy_price = given_prices[0];
|
|
|
|
|
|
|
|
|
|
// Main spike 1
|
|
|
|
|
min_pred = get_price(rate_min, buy_price) - 1;
|
|
|
|
|
max_pred = get_price(rate_max, buy_price) - 1;
|
|
|
|
|
if (!isNaN(given_prices[start])) {
|
|
|
|
|
if (given_prices[start] < min_pred - FUDGE_FACTOR || given_prices[start] > max_pred + FUDGE_FACTOR) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[start];
|
|
|
|
|
max_pred = given_prices[start];
|
|
|
|
|
}
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Main spike 2
|
|
|
|
|
min_pred = predicted_prices[start].min;
|
|
|
|
|
max_pred = intceil(2.0 * buy_price);
|
|
|
|
|
if (!isNaN(given_prices[start + 1])) {
|
|
|
|
|
if (given_prices[start + 1] < min_pred - FUDGE_FACTOR || given_prices[start + 1] > max_pred + FUDGE_FACTOR) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[start + 1];
|
|
|
|
|
max_pred = given_prices[start + 1];
|
|
|
|
|
}
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Main spike 3
|
|
|
|
|
min_pred = intceil(1.4 * buy_price) - 1;
|
|
|
|
|
max_pred = predicted_prices[start + 1].max - 1;
|
|
|
|
|
if (!isNaN(given_prices[start + 2])) {
|
|
|
|
|
if (given_prices[start + 2] < min_pred - FUDGE_FACTOR || given_prices[start + 2] > max_pred + FUDGE_FACTOR) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[start + 2];
|
|
|
|
|
max_pred = given_prices[start + 2];
|
|
|
|
|
}
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_phase_1_len, high_phase_2_len, dec_phase_2_len, high_phase_3_len) {
|
|
|
|
|
function*
|
|
|
|
|
generate_pattern_0_with_lengths(
|
|
|
|
|
given_prices, high_phase_1_len, dec_phase_1_len, high_phase_2_len,
|
|
|
|
|
dec_phase_2_len, high_phase_3_len) {
|
|
|
|
|
/*
|
|
|
|
|
// PATTERN 0: high, decreasing, high, decreasing, high
|
|
|
|
|
work = 2;
|
|
|
|
@ -84,8 +260,8 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
buy_price = given_prices[0];
|
|
|
|
|
var predicted_prices = [
|
|
|
|
|
const buy_price = given_prices[0];
|
|
|
|
|
const predicted_prices = [
|
|
|
|
|
{
|
|
|
|
|
min: buy_price,
|
|
|
|
|
max: buy_price,
|
|
|
|
@ -97,120 +273,45 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// High Phase 1
|
|
|
|
|
for (var i = 2; i < 2 + high_phase_1_len; i++) {
|
|
|
|
|
min_pred = Math.floor(0.9 * buy_price);
|
|
|
|
|
max_pred = Math.ceil(1.4 * buy_price);
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
if (!generate_individual_random_price(
|
|
|
|
|
given_prices, predicted_prices, 2, high_phase_1_len, 0.9, 1.4)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dec Phase 1
|
|
|
|
|
var min_rate = 6000;
|
|
|
|
|
var max_rate = 8000;
|
|
|
|
|
for (var i = 2 + high_phase_1_len; i < 2 + high_phase_1_len + dec_phase_1_len; i++) {
|
|
|
|
|
min_pred = Math.floor(min_rate * buy_price / 10000);
|
|
|
|
|
max_pred = Math.ceil(max_rate * buy_price / 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
min_rate = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
max_rate = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
min_rate -= 1000;
|
|
|
|
|
max_rate -= 400;
|
|
|
|
|
if (!generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices, 2 + high_phase_1_len, dec_phase_1_len,
|
|
|
|
|
0.6, 0.8, 0.04, 0.1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// High Phase 2
|
|
|
|
|
for (var i = 2 + high_phase_1_len + dec_phase_1_len; i < 2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len; i++) {
|
|
|
|
|
min_pred = Math.floor(0.9 * buy_price);
|
|
|
|
|
max_pred = Math.ceil(1.4 * buy_price);
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
if (!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)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dec Phase 2
|
|
|
|
|
var min_rate = 6000;
|
|
|
|
|
var max_rate = 8000;
|
|
|
|
|
for (var i = 2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len; i < 2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len + dec_phase_2_len; i++) {
|
|
|
|
|
min_pred = Math.floor(min_rate * buy_price / 10000);
|
|
|
|
|
max_pred = Math.ceil(max_rate * buy_price / 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
min_rate = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
max_rate = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
min_rate -= 1000;
|
|
|
|
|
max_rate -= 400;
|
|
|
|
|
if (!generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices,
|
|
|
|
|
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)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// High Phase 3
|
|
|
|
|
if (2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len + dec_phase_2_len + high_phase_3_len != 14) {
|
|
|
|
|
throw new Error("Phase lengths don't add up");
|
|
|
|
|
}
|
|
|
|
|
for (var i = 2 + high_phase_1_len + dec_phase_1_len + high_phase_2_len + dec_phase_2_len; i < 14; i++) {
|
|
|
|
|
min_pred = Math.floor(0.9 * buy_price);
|
|
|
|
|
max_pred = Math.ceil(1.4 * buy_price);
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
const prev_length = 2 + high_phase_1_len + dec_phase_1_len +
|
|
|
|
|
high_phase_2_len + dec_phase_2_len;
|
|
|
|
|
if (!generate_individual_random_price(
|
|
|
|
|
given_prices, predicted_prices, prev_length, 14 - prev_length, 0.9,
|
|
|
|
|
1.4)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield {
|
|
|
|
|
pattern_description: "Fluctuating",
|
|
|
|
|
pattern_number: 0,
|
|
|
|
@ -257,8 +358,8 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) {
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
buy_price = given_prices[0];
|
|
|
|
|
var predicted_prices = [
|
|
|
|
|
const buy_price = given_prices[0];
|
|
|
|
|
const predicted_prices = [
|
|
|
|
|
{
|
|
|
|
|
min: buy_price,
|
|
|
|
|
max: buy_price,
|
|
|
|
@ -269,54 +370,21 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) {
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
var min_rate = 8500;
|
|
|
|
|
var max_rate = 9000;
|
|
|
|
|
|
|
|
|
|
for (var i = 2; i < peak_start; i++) {
|
|
|
|
|
min_pred = Math.floor(min_rate * buy_price / 10000);
|
|
|
|
|
max_pred = Math.ceil(max_rate * buy_price / 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
min_rate = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
max_rate = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
min_rate -= 500;
|
|
|
|
|
max_rate -= 300;
|
|
|
|
|
if (!generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices, 2, peak_start - 2, 0.85, 0.9, 0.03,
|
|
|
|
|
0.05)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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]
|
|
|
|
|
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 (var i = peak_start; i < 14; i++) {
|
|
|
|
|
min_pred = Math.floor(min_randoms[i - peak_start] * buy_price);
|
|
|
|
|
max_pred = Math.ceil(max_randoms[i - peak_start] * buy_price);
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
for (let i = peak_start; i < 14; i++) {
|
|
|
|
|
if (!generate_individual_random_price(
|
|
|
|
|
given_prices, predicted_prices, i, 1, min_randoms[i - peak_start],
|
|
|
|
|
max_randoms[i - peak_start])) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
yield {
|
|
|
|
|
pattern_description: "Large spike",
|
|
|
|
@ -345,9 +413,8 @@ function* generate_pattern_2(given_prices) {
|
|
|
|
|
break;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
buy_price = given_prices[0];
|
|
|
|
|
var predicted_prices = [
|
|
|
|
|
const buy_price = given_prices[0];
|
|
|
|
|
const predicted_prices = [
|
|
|
|
|
{
|
|
|
|
|
min: buy_price,
|
|
|
|
|
max: buy_price,
|
|
|
|
@ -358,32 +425,11 @@ function* generate_pattern_2(given_prices) {
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
var min_rate = 8500;
|
|
|
|
|
var max_rate = 9000;
|
|
|
|
|
for (var i = 2; i < 14; i++) {
|
|
|
|
|
min_pred = Math.floor(min_rate * buy_price / 10000);
|
|
|
|
|
max_pred = Math.ceil(max_rate * buy_price / 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
min_rate = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
max_rate = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
min_rate -= 500;
|
|
|
|
|
max_rate -= 300;
|
|
|
|
|
if (!generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices, 2, 14 - 2, 0.85, 0.9, 0.03, 0.05)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield {
|
|
|
|
|
pattern_description: "Decreasing",
|
|
|
|
|
pattern_number: 2,
|
|
|
|
@ -423,8 +469,8 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
buy_price = given_prices[0];
|
|
|
|
|
var predicted_prices = [
|
|
|
|
|
const buy_price = given_prices[0];
|
|
|
|
|
const predicted_prices = [
|
|
|
|
|
{
|
|
|
|
|
min: buy_price,
|
|
|
|
|
max: buy_price,
|
|
|
|
@ -434,130 +480,30 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
|
|
|
|
|
max: buy_price,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
let probability = 1;
|
|
|
|
|
|
|
|
|
|
var min_rate = 4000;
|
|
|
|
|
var max_rate = 9000;
|
|
|
|
|
|
|
|
|
|
for (var i = 2; i < peak_start; i++) {
|
|
|
|
|
min_pred = Math.floor(min_rate * buy_price / 10000);
|
|
|
|
|
max_pred = Math.ceil(max_rate * buy_price / 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
min_rate = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
max_rate = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
min_rate -= 500;
|
|
|
|
|
max_rate -= 300;
|
|
|
|
|
if (!generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices, 2, peak_start - 2, 0.4, 0.9, 0.03,
|
|
|
|
|
0.05)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The peak
|
|
|
|
|
|
|
|
|
|
for (var i = peak_start; i < peak_start + 2; i++) {
|
|
|
|
|
min_pred = Math.floor(0.9 * buy_price);
|
|
|
|
|
max_pred = Math.ceil(1.4 * buy_price);
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
if (!generate_individual_random_price(
|
|
|
|
|
given_prices, predicted_prices, peak_start, 2, 0.9, 1.4)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Main spike 1
|
|
|
|
|
min_pred = Math.floor(1.4 * buy_price) - 1;
|
|
|
|
|
max_pred = Math.ceil(2.0 * buy_price) - 1;
|
|
|
|
|
if (!isNaN(given_prices[peak_start + 2])) {
|
|
|
|
|
if (given_prices[peak_start + 2] < min_pred || given_prices[peak_start + 2] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[peak_start + 2];
|
|
|
|
|
max_pred = given_prices[peak_start + 2];
|
|
|
|
|
if (!generate_peak_price(
|
|
|
|
|
given_prices, predicted_prices, peak_start + 2, 1.4, 2.0)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Main spike 2
|
|
|
|
|
min_pred = predicted_prices[peak_start + 2].min;
|
|
|
|
|
max_pred = Math.ceil(2.0 * buy_price);
|
|
|
|
|
if (!isNaN(given_prices[peak_start + 3])) {
|
|
|
|
|
if (given_prices[peak_start + 3] < min_pred || given_prices[peak_start + 3] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[peak_start + 3];
|
|
|
|
|
max_pred = given_prices[peak_start + 3];
|
|
|
|
|
}
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Main spike 3
|
|
|
|
|
min_pred = Math.floor(1.4 * buy_price) - 1;
|
|
|
|
|
max_pred = predicted_prices[peak_start + 3].max - 1;
|
|
|
|
|
if (!isNaN(given_prices[peak_start + 4])) {
|
|
|
|
|
if (given_prices[peak_start + 4] < min_pred || given_prices[peak_start + 4] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[peak_start + 4];
|
|
|
|
|
max_pred = given_prices[peak_start + 4];
|
|
|
|
|
}
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (peak_start + 5 < 14) {
|
|
|
|
|
var min_rate = 4000;
|
|
|
|
|
var max_rate = 9000;
|
|
|
|
|
|
|
|
|
|
for (var i = peak_start + 5; i < 14; i++) {
|
|
|
|
|
min_pred = Math.floor(min_rate * buy_price / 10000);
|
|
|
|
|
max_pred = Math.ceil(max_rate * buy_price / 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(given_prices[i])) {
|
|
|
|
|
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
|
|
|
|
|
// Given price is out of predicted range, so this is the wrong pattern
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
min_pred = given_prices[i];
|
|
|
|
|
max_pred = given_prices[i];
|
|
|
|
|
min_rate = minimum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
max_rate = maximum_rate_from_given_and_base(given_prices[i], buy_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicted_prices.push({
|
|
|
|
|
min: min_pred,
|
|
|
|
|
max: max_pred,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
min_rate -= 500;
|
|
|
|
|
max_rate -= 300;
|
|
|
|
|
if (!generate_decreasing_random_price(
|
|
|
|
|
given_prices, predicted_prices, peak_start + 5,
|
|
|
|
|
14 - (peak_start + 5), 0.4, 0.9, 0.03, 0.05)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -620,6 +566,27 @@ function analyze_possibilities(sell_prices, first_buy, previous_pattern) {
|
|
|
|
|
generated_possibilities = Array.from(generate_possibilities(sell_prices, first_buy));
|
|
|
|
|
generated_possibilities = get_probabilities(generated_possibilities, previous_pattern);
|
|
|
|
|
|
|
|
|
|
for (let poss of generated_possibilities) {
|
|
|
|
|
var weekMins = [];
|
|
|
|
|
var weekMaxes = [];
|
|
|
|
|
for (let day of poss.prices.slice(2)) {
|
|
|
|
|
weekMins.push(day.min);
|
|
|
|
|
weekMaxes.push(day.max);
|
|
|
|
|
}
|
|
|
|
|
poss.weekGuaranteedMinimum = Math.max(...weekMins);
|
|
|
|
|
poss.weekMax = Math.max(...weekMaxes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generated_possibilities.sort((a, b) => {
|
|
|
|
|
if (a.weekMax < b.weekMax) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (a.weekMax > b.weekMax) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
global_min_max = [];
|
|
|
|
|
for (var day = 0; day < 14; day++) {
|
|
|
|
|
prices = {
|
|
|
|
@ -637,31 +604,12 @@ function analyze_possibilities(sell_prices, first_buy, previous_pattern) {
|
|
|
|
|
global_min_max.push(prices);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generated_possibilities.push({
|
|
|
|
|
generated_possibilities.unshift({
|
|
|
|
|
pattern_description: "All patterns",
|
|
|
|
|
pattern_number: 4,
|
|
|
|
|
prices: global_min_max,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (let poss of generated_possibilities) {
|
|
|
|
|
var weekMins = [];
|
|
|
|
|
var weekMaxes = [];
|
|
|
|
|
for (let day of poss.prices.slice(2)) {
|
|
|
|
|
weekMins.push(day.min);
|
|
|
|
|
weekMaxes.push(day.max);
|
|
|
|
|
}
|
|
|
|
|
poss.weekGuaranteedMinimum = Math.max(...weekMins);
|
|
|
|
|
poss.weekMax = Math.max(...weekMaxes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generated_possibilities.sort((a, b) => {
|
|
|
|
|
if (a.weekMax < b.weekMax) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (a.weekMax > b.weekMax) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
weekGuaranteedMinimum: Math.min(...generated_possibilities.map(poss => poss.weekGuaranteedMinimum)),
|
|
|
|
|
weekMax: Math.max(...generated_possibilities.map(poss => poss.weekMax)),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return generated_possibilities;
|
|
|
|
|