feat: display %chance of each pattern if known

master
Lou Huang 5 years ago committed by Mike Bryant
parent 60c1f160d0
commit 63e6b1adec

@ -37,6 +37,33 @@
</span>
</div>
</div>
<div class="row">
<div class="col s12">
<h5>Probability</h5>
<div class="row">
<div class="col s4">
<div class="input-field">
<select id="previous_pattern">
<option value="-1" selected>(unknown)</option>
<!-- Choices are ordered by increasing desirability, not code ID order -->
<option value="2">Decreasing</option>
<option value="0">Rollercoaster</option>
<option value="3">Small spike</option>
<option value="1">Large spike</option>
</select>
<label for="previous_pattern">Last weeks pattern</label>
</div>
</div>
<div class="col s6">
<div class="input-field">
<span>
<b>Last weeks pattern</b> affects the probability of patterns for this week. If you know it, select it to see probabilities for this week. <em>(optional)</em>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<h5>Daisy Mae</h5>
@ -152,6 +179,7 @@
<thead>
<tr>
<th rowspan="2">Pattern</th>
<th rowspan="2">% Chance</th>
<th rowspan="2">Sunday</th>
<th colspan="2">Monday</th>
<th colspan="2">Tuesday</th>

@ -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,
});

@ -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 = "<tr><td>" + poss.pattern_description + "</td>"
out_line += `<td>${Number.isFinite(poss.probability) ? ((poss.probability * 100).toPrecision(3) + '%') : '—'}</td>`;
for (let day of poss.prices.slice(1)) {
if (day.min !== day.max) {
out_line += `<td>${day.min}..${day.max}</td>`;
@ -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);

Loading…
Cancel
Save