Skip to content

Instantly share code, notes, and snippets.

@va2577
Created May 9, 2018 12:55
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/3323ca6afc2c9e6ca64663ded2246dc0 to your computer and use it in GitHub Desktop.
Save va2577/3323ca6afc2c9e6ca64663ded2246dc0 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="rab">0</span></td>
<td><span id="rab2">0</span></td>
</tr>
<tr>
<th>勝率</th>
<td><span id="rwr">0</span></td>
<td><span id="rwr2">0</span></td>
</tr>
<tr>
<th>期待値</th>
<td><span id="rev">0</span></td>
<td><span id="rev2">0</span></td>
</tr>
<tr>
<th>平均月利</th>
<td><span id="rm">0</span></td>
<td><span id="rm2">0</span></td>
</tr>
<tr>
<th>平均年利</th>
<td><span id="ra">0</span></td>
<td><span id="ra2">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: number => number.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 = id => {
const e = document.getElementById(id);
const isValid = !(e.value.length === 0 || isNaN(e.value));
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((p, cv) => {
p[cv] = Number(document.getElementById(cv).value);
return p;
}, {});
},
w: wr => Math.random() < wr,
rrr: (ap, al) => ap / al,
pl: (ab, fr, w, rrr) => Math.floor(ab * fr * (w ? rrr : -1)),
ab: (ab, fr, w, rrr) => ab + local.pl(ab, fr, w, rrr),
ab2: (ab, fr, ev, i) => Math.floor(ab * Math.pow(1 + fr * ev, i)),
wr: array => array.filter(v => v).length / array.length,
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: (parameters) => {
const result = {};
const w = [...Array(parameters.t).keys()].map(() => local.w(parameters.wr));
const rrr = local.rrr(parameters.ap, parameters.al);
result.ab = w.reduce((p, cv) => {
p.push(local.ab(local.last(p), parameters.fr, cv, rrr));
return p;
}, Array.of(parameters.ab));
result.wr = local.wr(w);
result.ev = local.ev(result.wr, rrr);
result.monthly = local.pr(result.ab, parameters.o, true, false);
result.annual = local.pr(result.ab, parameters.o, false, true);
return result;
},
simulate2: (parameters) => {
const result = {};
const rrr = local.rrr(parameters.ap, parameters.al);
result.wr = parameters.wr;
result.ev = local.ev(parameters.wr, rrr);
result.ab = [...Array(parameters.t + 1).keys()]
.map((v, i, a) => local.ab2(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('rab').textContent = local.last(result.ab).toLocaleString();
document.getElementById('rwr').textContent = local.round(result.wr, 2);
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();
const result2 = local.simulate2(parameters);
if (!result2.hasOwnProperty('ab')) return;
local.chart.data.datasets[1].data = result2.ab;
local.chart.data.labels = result2.ab.map((v, i) => i);
local.chart.update();
document.getElementById('rab2').textContent = local.last(result2.ab).toLocaleString();
document.getElementById('rwr2').textContent = local.round(result2.wr, 2);
document.getElementById('rev2').textContent = local.round(result2.ev, 2);
document.getElementById('rm2').textContent = local.round(result2.monthly, 2).toLocaleString();
document.getElementById('ra2').textContent = local.round(result2.annual, 2).toLocaleString();
}
};
document.getElementById('simulate').addEventListener('click', () => {
local.plot();
});
window.addEventListener('load', () => {
const ctx = document.getElementById('canvas').getContext('2d');
const chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
const data = {
datasets: [
{
backgroundColor: chartColors.red,
borderColor: chartColors.red,
data: [],
fill: false,
label: 'ランダム'
},
{
backgroundColor: chartColors.blue,
borderColor: chartColors.blue,
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