Skip to content

Instantly share code, notes, and snippets.

@va2577
Created May 8, 2018 07:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save va2577/af6d755efbe325e34b162756b960e9a7 to your computer and use it in GitHub Desktop.
Save va2577/af6d755efbe325e34b162756b960e9a7 to your computer and use it in GitHub Desktop.
期待値による口座残高の推移
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>simulation</title>
<style>
input#simulate {
width: 100%;
}
input.error {
background-color: red;
}
span#message {
color: red;
}
</style>
</head>
<body>
<div>
<form>
<table>
<tr>
<th>定率</th>
<td><input type="text" id="fr" placeholder="0.02" value="0.02"></td>
</tr>
<tr>
<th>口座残高</th>
<td><input type="text" id="ab" placeholder="1000000" value="1000000"></td>
</tr>
<tr>
<th>勝率</th>
<td><input type="text" id="wr" placeholder="0.30" value="0.30"></td>
</tr>
<tr>
<th>平均利益</th>
<td><input type="text" id="ap" placeholder="3" value="3"></td>
</tr>
<tr>
<th>平均損失</th>
<td><input type="text" id="al" placeholder="1" value="1"></td>
</tr>
<tr>
<th>機会</th>
<td><input type="text" id="o" placeholder="10" value="10"></td>
</tr>
<tr>
<th>試行回数</th>
<td><input type="text" id="t" placeholder="100" value="100"></td>
</tr>
<tr>
<td colspan="2"><input type="button" id="simulate" value="シミュレート"></td>
</tr>
</table>
</form>
<span id="message"></span>
</div>
<div height="320" width="640">
<canvas id="canvas"></canvas>
</div>
<div>
<table>
<tr>
<th>口座残高</th>
<td><span id="rb">0</span></td>
</tr>
<tr>
<th>勝率</th>
<td><span id="rwr">0</span></td>
</tr>
<tr>
<th>期待値</th>
<td><span id="rev">0</span></td>
</tr>
<tr>
<th>平均月利</th>
<td><span id="rm">0</span></td>
</tr>
<tr>
<th>平均年利</th>
<td><span id="ra">0</span></td>
</tr>
</table>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script>
const local = {
chart: null,
comma: v => v.toLocaleString(),
round: (number, precision) => {
const factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
},
last: array => array[array.length - 1],
sum: array => array.reduce((p, cv) => p + cv, 0),
average: array => local.sum(array) / array.length,
validate: ids => {
document.getElementById('message').textContent = '';
const entered = (c) => {
const e = document.getElementById(c);
const v = e.value;
const isValid = !(v.length === 0 || isNaN(v));
e.className = isValid ? '' : 'error';
return isValid;
};
if (!ids.every(entered)) {
document.getElementById('message').textContent = 'パラメーターを数字で入力してください。';
return false;
}
if (Number(document.getElementById('t').value) > 2000) {
document.getElementById('message').textContent = '試行回数は 2000 以内で入力してください。';
return false;
}
return true;
},
parameters: ids => {
return ids.reduce((a, c) => {
a[c] = Number(document.getElementById(c).value);
return a;
}, {});
},
rrr: (ap, al) => ap / al,
b: (b, fr, ev, i) => Math.floor(b * Math.pow(1 + fr * ev, i)),
ev: (wr, rrr) => (wr * rrr / 1) - (1 - wr * (1 / 1)),
pr: (ab, o, monthly, annual) => {
const times = monthly ? o : annual ? o * 12 : 0;
const p = [...Array(Math.ceil(ab.length / times)).keys()]
.map(v => ab.filter((v2, i2) => v * times <= i2 && i2 <= (v + 1) * times))
.filter(v => v.length > 1)
.map(v => (local.last(v) - v[0]) / v[0]);
return local.average(p);
},
simulate: function (parameters) {
const result = {};
result.rrr = local.rrr(parameters.ap, parameters.al);
result.ev = local.ev(parameters.wr, result.rrr);
result.ab = [...Array(parameters.t + 1).keys()]
.map((v, i, a) => local.b(parameters.ab, parameters.fr, result.ev, i));
result.monthly = local.pr(result.ab, parameters.o, true, false);
result.annual = local.pr(result.ab, parameters.o, false, true);
return result;
},
plot: () => {
const ids = ['fr', 'ab', 'wr', 'ap', 'al', 'o', 't'];
if (!local.validate(ids)) return;
const parameters = local.parameters(ids);
const result = local.simulate(parameters);
if (!result.hasOwnProperty('ab')) return;
local.chart.data.datasets[0].data = result.ab;
local.chart.data.labels = result.ab.map((v, i) => i);
local.chart.update();
document.getElementById('rb').textContent = local.last(result.ab).toLocaleString();
document.getElementById('rev').textContent = local.round(result.ev, 2);
document.getElementById('rm').textContent = local.round(result.monthly, 2).toLocaleString();
document.getElementById('ra').textContent = local.round(result.annual, 2).toLocaleString();
}
};
document.getElementById('simulate').addEventListener('click', () => {
local.plot();
});
window.addEventListener('load', () => {
const ctx = document.getElementById('canvas').getContext('2d');
const data = {
datasets: [{
data: [],
fill: false,
label: '口座残高'
}],
labels: []
};
const options = {
scales: {
yAxes: [{
ticks: {
userCallback: local.comma
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => data.datasets[tooltipItem.datasetIndex].label + ': ' + local.comma(tooltipItem.yLabel)
}
}
};
local.chart = new Chart(ctx, {
data: data,
options: options,
type: 'line'
});
local.plot();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment