frequi_origin/src/views/Backtesting.vue

362 lines
10 KiB
Vue
Raw Normal View History

2020-07-26 11:44:34 +00:00
<template>
2020-12-05 15:32:44 +00:00
<div class="container-fluid">
2021-01-06 12:13:02 +00:00
<h2 class="mt-3">Backtesting</h2>
2020-12-05 15:32:44 +00:00
<div class="container">
2021-01-06 12:13:02 +00:00
<div class="row mx-5 d-flex flex-wrap justify-content-center mb-4">
2020-12-05 15:32:44 +00:00
<b-form-radio
v-model="btFormMode"
name="bt-form-radios"
button
2021-01-06 12:13:02 +00:00
class="mx-1"
2020-12-05 15:32:44 +00:00
value="run"
:disabled="!canRunBacktest"
>Run backtest</b-form-radio
2020-09-25 04:22:34 +00:00
>
2020-12-05 15:32:44 +00:00
<b-form-radio
v-model="btFormMode"
name="bt-form-radios"
button
2021-01-06 12:13:02 +00:00
class="mx-1"
2020-12-05 15:32:44 +00:00
value="results"
:disabled="!hasBacktestResult"
>Analyze result</b-form-radio
>
<b-form-radio
v-model="btFormMode"
name="bt-form-radios"
button
2021-01-06 12:13:02 +00:00
class="mx-1"
2020-12-05 15:32:44 +00:00
value="visualize-summary"
:disabled="!hasBacktestResult"
>Visualize summary</b-form-radio
>
<b-form-radio
v-model="btFormMode"
name="bt-form-radios"
button
2021-01-06 12:13:02 +00:00
class="mx-1"
2020-12-05 15:32:44 +00:00
value="visualize"
:disabled="!hasBacktestResult"
>Visualize result</b-form-radio
>
</div>
2020-09-25 04:22:34 +00:00
2021-01-06 12:13:02 +00:00
<div v-if="btFormMode == 'run'" class="row d-flex flex-column">
2020-12-05 15:32:44 +00:00
<StrategyList v-model="strategy"></StrategyList>
2020-09-25 04:22:34 +00:00
2020-12-05 15:32:44 +00:00
<b-card bg-variant="light" class="w-60" :disabled="backtestRunning">
<!-- Backtesting parameters -->
2020-09-25 04:22:34 +00:00
<b-form-group
2020-12-05 15:32:44 +00:00
label-cols-lg="2"
label="Backtest params"
label-size="sm"
label-class="font-weight-bold pt-0"
class="mb-0"
2020-07-27 05:19:45 +00:00
>
2020-12-05 15:32:44 +00:00
<b-form-group
label-cols-sm="5"
label="Timeframe:"
label-align-sm="right"
2021-01-06 19:25:38 +00:00
label-for="timeframe-select"
2020-12-05 15:32:44 +00:00
>
<b-form-select
id="timeframe-select"
2021-01-02 14:10:10 +00:00
v-model="selectedTimeframe"
2020-12-05 15:32:44 +00:00
placeholder="Use strategy default"
:options="availableTimeframes"
></b-form-select>
</b-form-group>
<b-form-group
label-cols-sm="5"
label="Max open trades:"
label-align-sm="right"
label-for="max-open-trades"
>
<b-form-input
id="max-open-trades"
2020-12-08 18:35:06 +00:00
v-model="maxOpenTrades"
2020-12-05 15:32:44 +00:00
placeholder="Use strategy default"
type="number"
></b-form-input>
</b-form-group>
<b-form-group
label-cols-sm="5"
label="Stake amount:"
label-align-sm="right"
label-for="stake-amount"
>
<b-form-input
id="stake-amount"
2020-12-08 18:35:06 +00:00
v-model="stakeAmount"
2020-12-05 15:32:44 +00:00
type="number"
placeholder="Use strategy default"
step="0.01"
></b-form-input>
</b-form-group>
2021-01-06 19:25:38 +00:00
<b-form-group
label-cols-sm="5"
label="Enable Protections:"
label-align-sm="right"
label-for="enable-protections"
>
<b-form-checkbox
id="enable-protections"
v-model="enableProtections"
:options="availableTimeframes"
></b-form-checkbox>
</b-form-group>
2020-12-08 18:35:06 +00:00
<!-- <b-form-group label-cols-sm="5" label="Fee:" label-align-sm="right" label-for="fee">
2020-12-05 15:32:44 +00:00
<b-form-input
id="fee"
type="number"
placeholder="Use exchange default"
step="0.01"
></b-form-input>
2020-12-08 18:35:06 +00:00
</b-form-group> -->
2020-09-25 04:22:34 +00:00
</b-form-group>
2020-12-05 15:32:44 +00:00
</b-card>
2021-01-06 12:13:02 +00:00
<TimeRangeSelect v-model="timerange" class="mt-2"></TimeRangeSelect>
<h3 class="mt-3">Backtesting summary</h3>
<div class="d-flex justify-content-center">
<b-button
variant="primary"
:disabled="backtestRunning"
class="mx-1"
@click="clickBacktest"
>
2020-12-05 15:32:44 +00:00
Start backtest
</b-button>
2021-01-06 12:13:02 +00:00
<b-button
variant="primary"
:disabled="backtestRunning"
class="mx-1"
@click="pollBacktest"
>
2020-12-05 15:32:44 +00:00
Load backtest result
</b-button>
2021-01-06 12:13:02 +00:00
<b-button variant="primary" class="mx-1" @click="removeBacktest">Reset Backtest</b-button>
2020-12-05 15:32:44 +00:00
</div>
2020-09-25 04:22:34 +00:00
</div>
</div>
<div v-if="hasBacktestResult && btFormMode == 'results'" class="text-center w-100 mt-2">
2021-01-14 07:04:28 +00:00
<div class="d-flex">
<b-list-group-item
v-for="[key, strat] in Object.entries(backtestHistory)"
:key="key"
button
class="d-flex justify-content-between align-items-center py-1"
>
{{ key }} {{ strat.total_trades }} {{ formatPercent(strat.profit_total) }}
</b-list-group-item>
</div>
2020-09-25 04:22:34 +00:00
<BacktestResultView :strategy="strategy" :backtest-result="selectedBacktestResult" />
</div>
2020-11-01 12:58:16 +00:00
<div
v-if="hasBacktestResult && btFormMode == 'visualize-summary'"
2021-01-06 13:51:04 +00:00
class="text-center w-100 mt-2 d-flex flex-column"
2020-11-01 12:58:16 +00:00
>
2021-01-06 13:51:04 +00:00
<TradesLogChart :trades="selectedBacktestResult.trades" class="trades-log" />
2020-11-01 12:58:16 +00:00
<CumProfitChart
:trades="selectedBacktestResult.trades"
profit-column="profit_abs"
2021-01-06 13:51:04 +00:00
class="cum-profit"
2020-11-01 12:58:16 +00:00
:show-title="true"
/>
</div>
2020-12-05 16:42:22 +00:00
<div
v-if="hasBacktestResult && btFormMode == 'visualize'"
class="container-fluid row text-center w-100 mt-2"
>
<PairSummary
class="col-md-2"
:pairlist="selectedBacktestResult.pairlist"
:trades="selectedBacktestResult.trades"
sort-method="profit"
2020-12-05 16:42:22 +00:00
/>
2020-09-25 04:22:34 +00:00
<CandleChartContainer
:available-pairs="selectedBacktestResult.pairlist"
:historic-view="!!true"
:timeframe="timeframe"
:plot-config="selectedPlotConfig"
:timerange="timerange"
:strategy="strategy"
:trades="selectedBacktestResult.trades"
2020-12-05 16:42:22 +00:00
class="col-md-10 candle-chart-container"
2020-09-25 04:22:34 +00:00
>
</CandleChartContainer>
2020-07-26 17:35:56 +00:00
</div>
2020-07-26 11:44:34 +00:00
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import { namespace } from 'vuex-class';
import TimeRangeSelect from '@/components/ftbot/TimeRangeSelect.vue';
2020-07-26 17:35:56 +00:00
import BacktestResultView from '@/components/ftbot/BacktestResultView.vue';
2020-09-12 17:21:35 +00:00
import CandleChartContainer from '@/components/charts/CandleChartContainer.vue';
2020-08-08 18:21:47 +00:00
import StrategyList from '@/components/ftbot/StrategyList.vue';
2020-11-01 12:47:57 +00:00
import ValuePair from '@/components/ftbot/ValuePair.vue';
2020-11-01 12:58:16 +00:00
import CumProfitChart from '@/components/charts/CumProfitChart.vue';
2021-01-06 13:51:04 +00:00
import TradesLogChart from '@/components/charts/TradesLog.vue';
2020-12-05 16:42:22 +00:00
import PairSummary from '@/components/ftbot/PairSummary.vue';
2020-07-26 17:35:56 +00:00
2020-07-27 05:19:45 +00:00
import {
BacktestPayload,
BacktestResult,
PairHistoryPayload,
PlotConfig,
StrategyBacktestResult,
} from '@/types';
import { getCustomPlotConfig, getPlotConfigName } from '@/shared/storage';
2021-01-14 07:04:28 +00:00
import { formatPercent } from '@/shared/formatters';
2020-07-26 11:44:34 +00:00
const ftbot = namespace('ftbot');
@Component({
2020-11-01 12:47:57 +00:00
components: {
BacktestResultView,
TimeRangeSelect,
CandleChartContainer,
2020-11-01 12:58:16 +00:00
CumProfitChart,
2021-01-06 13:51:04 +00:00
TradesLogChart,
2020-11-01 12:47:57 +00:00
StrategyList,
ValuePair,
2020-12-05 16:42:22 +00:00
PairSummary,
2020-11-01 12:47:57 +00:00
},
2020-07-26 11:44:34 +00:00
})
2020-07-26 17:35:56 +00:00
export default class Backtesting extends Vue {
pollInterval: number | null = null;
2020-07-26 11:44:34 +00:00
2020-09-25 04:22:34 +00:00
availableTimeframes = [
'1m',
'3m',
'5m',
'15m',
'30m',
'1h',
'2h',
'4h',
'6h',
'8h',
'12h',
'1d',
'3d',
'1w',
'2w',
'1M',
'1y',
];
2021-01-02 14:10:10 +00:00
selectedTimeframe = '';
2020-09-25 04:22:34 +00:00
strategy = '';
2021-01-06 19:25:38 +00:00
timerange = '';
enableProtections = false;
maxOpenTrades = '';
stakeAmount = '';
2020-12-05 15:32:44 +00:00
btFormMode = 'run';
2020-07-26 17:35:56 +00:00
2020-07-27 05:19:45 +00:00
selectedPlotConfig: PlotConfig = getCustomPlotConfig(getPlotConfigName());
2020-07-26 11:44:34 +00:00
@ftbot.State backtestRunning!: boolean;
2020-07-26 17:35:56 +00:00
@ftbot.State backtestResult!: BacktestResult;
2021-01-14 07:04:28 +00:00
@ftbot.State backtestHistory!: StrategyBacktestResult[];
2020-07-27 05:19:45 +00:00
@ftbot.State history;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ftbot.Action public getPairHistory!: (payload: PairHistoryPayload) => void;
2020-07-26 17:35:56 +00:00
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ftbot.Action startBacktest!: (payload: BacktestPayload) => void;
2020-07-26 11:44:34 +00:00
@ftbot.Action pollBacktest!: () => void;
@ftbot.Action removeBacktest!: () => void;
2021-01-14 07:04:28 +00:00
formatPercent = formatPercent;
2020-09-25 04:22:34 +00:00
get canRunBacktest() {
// TODO: Analyze if parameters and strategy has been selected.
return true;
}
2020-07-26 17:35:56 +00:00
get hasBacktestResult() {
return Object.keys(this.backtestResult).length !== 0;
}
2020-07-27 05:19:45 +00:00
get selectedBacktestResult(): StrategyBacktestResult {
return this.backtestResult.strategy[this.strategy] || {};
}
2020-08-08 18:21:47 +00:00
get timeframe(): string {
try {
return this.backtestResult.strategy[this.strategy].timeframe;
} catch (err) {
return '';
}
}
2020-07-26 11:44:34 +00:00
clickBacktest() {
const btPayload: BacktestPayload = {
2020-07-26 17:35:56 +00:00
strategy: this.strategy,
2020-07-26 11:44:34 +00:00
timerange: this.timerange,
2021-01-06 19:25:38 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
enable_protections: this.enableProtections,
2020-07-26 11:44:34 +00:00
};
const openTradesInt = parseInt(this.maxOpenTrades, 10);
if (openTradesInt) {
2020-12-08 18:35:06 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
btPayload.max_open_trades = openTradesInt;
2020-12-08 18:35:06 +00:00
}
const stakeAmountInt = Number(this.stakeAmount);
if (stakeAmountInt) {
2020-12-08 18:35:06 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
btPayload.stake_amount = stakeAmountInt;
2020-12-08 18:35:06 +00:00
}
2021-01-02 14:10:10 +00:00
if (this.selectedTimeframe) {
btPayload.timeframe = this.selectedTimeframe;
}
2020-12-08 18:35:06 +00:00
2020-07-26 11:44:34 +00:00
this.startBacktest(btPayload);
}
@Watch('backtestRunning')
backtestRunningChanged() {
if (this.backtestRunning === true) {
2020-07-26 17:35:56 +00:00
this.pollInterval = window.setInterval(this.pollBacktest, 1000);
2020-07-26 11:44:34 +00:00
} else if (this.pollInterval) {
clearInterval(this.pollInterval);
this.pollInterval = null;
}
}
}
</script>
<style scoped>
.candle-chart-container {
height: 640px !important;
}
2021-01-06 13:51:04 +00:00
.cum-profit {
height: 350px;
max-height: 350px;
}
.trades-log {
height: 350px;
max-height: 350px;
2020-11-01 12:58:16 +00:00
}
</style>