diff --git a/index.html b/index.html index 99944e2..ded86e6 100644 --- a/index.html +++ b/index.html @@ -37,6 +37,33 @@ +
+
+
Probability
+
+
+
+ + +
+
+
+
+ + Last week’s pattern affects the probability of patterns for this week. If you know it, select it to see probabilities for this week. (optional) + +
+
+
+
+
Daisy Mae
@@ -152,6 +179,7 @@ Pattern + % Chance Sunday Monday Tuesday diff --git a/js/predictions.js b/js/predictions.js index 3b3e4ae..5fa5a48 100644 --- a/js/predictions.js +++ b/js/predictions.js @@ -1,3 +1,37 @@ +const PATTERN = { + ROLLERCOASTER: 0, + LARGE_SPIKE: 1, + DECREASING: 2, + SMALL_SPIKE: 3, +}; + +const PROBABILITY_MATRIX = { + [PATTERN.ROLLERCOASTER]: { + [PATTERN.ROLLERCOASTER]: 0.20, + [PATTERN.LARGE_SPIKE]: 0.30, + [PATTERN.DECREASING]: 0.15, + [PATTERN.SMALL_SPIKE]: 0.35, + }, + [PATTERN.LARGE_SPIKE]: { + [PATTERN.ROLLERCOASTER]: 0.50, + [PATTERN.LARGE_SPIKE]: 0.05, + [PATTERN.DECREASING]: 0.20, + [PATTERN.SMALL_SPIKE]: 0.25, + }, + [PATTERN.DECREASING]: { + [PATTERN.ROLLERCOASTER]: 0.25, + [PATTERN.LARGE_SPIKE]: 0.45, + [PATTERN.DECREASING]: 0.05, + [PATTERN.SMALL_SPIKE]: 0.25, + }, + [PATTERN.SMALL_SPIKE]: { + [PATTERN.ROLLERCOASTER]: 0.45, + [PATTERN.LARGE_SPIKE]: 0.25, + [PATTERN.DECREASING]: 0.15, + [PATTERN.SMALL_SPIKE]: 0.15, + }, +}; + function minimum_rate_from_given_and_base(given_price, buy_price) { return 10000 * (given_price - 1) / buy_price; } @@ -177,7 +211,7 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph }); } yield { - pattern_description: "high, decreasing, high, decreasing, high", + pattern_description: "Rollercoaster", pattern_number: 0, prices: predicted_prices }; @@ -285,7 +319,7 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) { }); } yield { - pattern_description: "decreasing middle, high spike, random low", + pattern_description: "Large spike", pattern_number: 1, prices: predicted_prices }; @@ -351,7 +385,7 @@ function* generate_pattern_2(given_prices) { max_rate -= 300; } yield { - pattern_description: "consistently decreasing", + pattern_description: "Decreasing", pattern_number: 2, prices: predicted_prices }; @@ -531,7 +565,7 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) { } yield { - pattern_description: "decreasing, spike, decreasing", + pattern_description: "Small spike", pattern_number: 3, prices: predicted_prices }; @@ -564,8 +598,31 @@ function* generate_possibilities(sell_prices, first_buy) { } } -function analyze_possibilities(sell_prices, first_buy) { +function get_probabilities(possibilities, previous_pattern) { + if (typeof previous_pattern === 'undefined' || Number.isNaN(previous_pattern) || previous_pattern === null || previous_pattern < 0 || previous_pattern > 3) { + return possibilities + } + + var unique = (value, index, self) => { + return self.indexOf(value) === index; + } + var max_percent = possibilities.map(function (poss) { + return poss.pattern_number; + }).filter(unique).map(function(poss) { + return PROBABILITY_MATRIX[previous_pattern][poss]; + }).reduce(function (prev, current) { + return prev + current; + }, 0); + + return possibilities.map(function (poss) { + poss.probability = PROBABILITY_MATRIX[previous_pattern][poss.pattern_number] / max_percent; + return poss; + }); +} + +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); global_min_max = []; for (var day = 0; day < 14; day++) { @@ -585,7 +642,7 @@ function analyze_possibilities(sell_prices, first_buy) { } generated_possibilities.push({ - pattern_description: "predicted min/max across all patterns", + pattern_description: "All patterns", pattern_number: 4, prices: global_min_max, }); diff --git a/js/scripts.js b/js/scripts.js index 4a99fbe..7dd9bf6 100644 --- a/js/scripts.js +++ b/js/scripts.js @@ -10,10 +10,12 @@ const getSellFields = function () { const sell_inputs = getSellFields() const buy_input = $("#buy") const first_buy_field = $("#first_buy"); +const previous_pattern_input = $("#previous_pattern"); //Functions -const fillFields = function (prices, first_buy) { +const fillFields = function (prices, first_buy, previous_pattern) { first_buy_field.prop("checked", first_buy); + previous_pattern_input.val(previous_pattern); buy_input.focus(); buy_input.val(prices[0] || '') @@ -36,10 +38,11 @@ const initialize = function () { try { const prices = getPrices() const first_buy = getFirstBuyState(); + const previous_pattern = getPreviousPatternState(); if (prices === null) { - fillFields([], first_buy) + fillFields([], first_buy, previous_pattern) } else { - fillFields(prices, first_buy) + fillFields(prices, first_buy, previous_pattern) } $(document).trigger("input"); } catch (e) { @@ -48,15 +51,19 @@ const initialize = function () { $("#reset").on("click", function () { first_buy_field.prop('checked', false); + $("select").val(null); $("input").val(null).trigger("input"); }) + + $('select').formSelect(); } -const updateLocalStorage = function (prices, first_buy) { +const updateLocalStorage = function (prices, first_buy, previous_pattern) { try { if (prices.length !== 14) throw "The data array needs exactly 14 elements to be valid" localStorage.setItem("sell_prices", JSON.stringify(prices)) localStorage.setItem("first_buy", JSON.stringify(first_buy)); + localStorage.setItem("previous_pattern", JSON.stringify(previous_pattern)); } catch (e) { console.error(e) } @@ -71,6 +78,10 @@ const getFirstBuyState = function () { return JSON.parse(localStorage.getItem('first_buy')) } +const getPreviousPatternState = function () { + return JSON.parse(localStorage.getItem('previous_pattern')) +} + const getPricesFromLocalstorage = function () { try { const sell_prices = JSON.parse(localStorage.getItem("sell_prices")); @@ -112,14 +123,15 @@ const getSellPrices = function () { }) } -const calculateOutput = function (data, first_buy) { +const calculateOutput = function (data, first_buy, previous_pattern) { if (isEmpty(data)) { $("#output").html(""); return; } let output_possibilities = ""; - for (let poss of analyze_possibilities(data, first_buy)) { + for (let poss of analyze_possibilities(data, first_buy, previous_pattern)) { var out_line = "" + poss.pattern_description + "" + out_line += `${Number.isFinite(poss.probability) ? ((poss.probability * 100).toPrecision(3) + '%') : '—'}`; for (let day of poss.prices.slice(1)) { if (day.min !== day.max) { out_line += `${day.min}..${day.max}`; @@ -138,15 +150,17 @@ const update = function () { const sell_prices = getSellPrices(); const buy_price = parseInt(buy_input.val()); const first_buy = first_buy_field.is(":checked"); + const previous_pattern = parseInt(previous_pattern_input.val()); buy_input.prop('disabled', first_buy); const prices = [buy_price, buy_price, ...sell_prices]; if (!window.price_from_query) { - updateLocalStorage(prices, first_buy); + updateLocalStorage(prices, first_buy, previous_pattern); } - calculateOutput(prices, first_buy); + calculateOutput(prices, first_buy, previous_pattern); } $(document).ready(initialize); $(document).on("input", update); +$(previous_pattern_input).on("change", update);