mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-26 21:15:15 +00:00
Merge pull request #1550 from freqtrade/feat/backtest-comparison
Add backtest comparison view, allowing the comparison of multiple strategies
This commit is contained in:
commit
cb0cd62d72
63
src/components/ftbot/BacktestResultComparison.vue
Normal file
63
src/components/ftbot/BacktestResultComparison.vue
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<template>
|
||||||
|
<div class="px-0 mw-100">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<h3>Backtest-result comparison</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="d-flex">
|
||||||
|
<div v-for="[key, result] in Object.entries(backtestResults)" :key="key" class="border m-1">
|
||||||
|
<BacktestResultSelectEntry :backtest-result="result" />
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="d-flex flex-column text-start ms-0 me-2 gap-2">
|
||||||
|
<div class="d-flex flex-column flex-xl-row">
|
||||||
|
<div class="px-0 px-xl-0 pt-2 pt-xl-0 ps-xl-1 flex-fill">
|
||||||
|
<b-table bordered :items="backtestResultStats" :fields="backtestResultFields">
|
||||||
|
<template
|
||||||
|
v-for="[key, result] in Object.entries(backtestResults)"
|
||||||
|
#[`head(${key})`]
|
||||||
|
:key="key"
|
||||||
|
>
|
||||||
|
<BacktestResultSelectEntry :backtest-result="result" />
|
||||||
|
</template>
|
||||||
|
</b-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { BacktestResultInMemory } from '@/types';
|
||||||
|
import { formatObjectForTable } from '@/shared/objectToTableItems';
|
||||||
|
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { generateBacktestMetricRows } from '@/shared/backtestMetrics';
|
||||||
|
import { TableField } from 'bootstrap-vue-next';
|
||||||
|
import BacktestResultSelectEntry from '@/components/ftbot/BacktestResultSelectEntry.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
backtestResults: { required: true, type: Object as () => Record<string, BacktestResultInMemory> },
|
||||||
|
});
|
||||||
|
|
||||||
|
const backtestResultStats = computed(() => {
|
||||||
|
const values = {};
|
||||||
|
Object.entries(props.backtestResults).forEach(([key, result]) => {
|
||||||
|
const tmp = generateBacktestMetricRows(result.strategy);
|
||||||
|
values[key] = tmp;
|
||||||
|
});
|
||||||
|
console.log(values);
|
||||||
|
// return '';
|
||||||
|
return formatObjectForTable(values, 'metric');
|
||||||
|
});
|
||||||
|
|
||||||
|
const backtestResultFields = computed<TableField[]>(() => {
|
||||||
|
const res = [{ key: 'metric', label: 'Metric' }];
|
||||||
|
Object.entries(props.backtestResults).forEach(([key, value]) => {
|
||||||
|
res.push({ key, label: value.metadata.strategyName });
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -56,6 +56,7 @@
|
||||||
<b-form-input
|
<b-form-input
|
||||||
id="starting-capital"
|
id="starting-capital"
|
||||||
v-model="btStore.startingCapital"
|
v-model="btStore.startingCapital"
|
||||||
|
placeholder="Use config default"
|
||||||
type="number"
|
type="number"
|
||||||
step="0.001"
|
step="0.001"
|
||||||
></b-form-input>
|
></b-form-input>
|
||||||
|
@ -66,20 +67,19 @@
|
||||||
label-align-sm="right"
|
label-align-sm="right"
|
||||||
label-for="stake-amount"
|
label-for="stake-amount"
|
||||||
>
|
>
|
||||||
<div class="d-flex">
|
<div class="d-flex align-items-center">
|
||||||
<b-form-checkbox
|
<div style="flex-basis: 100%" class="d-flex">
|
||||||
id="stake-amount-bool"
|
<b-form-checkbox id="stake-amount-bool" v-model="btStore.stakeAmountUnlimited"
|
||||||
v-model="btStore.stakeAmountUnlimited"
|
>Unlimited stake</b-form-checkbox
|
||||||
class="col-md-6"
|
>
|
||||||
>Unlimited stake</b-form-checkbox
|
</div>
|
||||||
>
|
|
||||||
|
|
||||||
<b-form-input
|
<b-form-input
|
||||||
id="stake-amount"
|
id="stake-amount"
|
||||||
v-model="btStore.stakeAmount"
|
v-model="btStore.stakeAmount"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="Use strategy default"
|
placeholder="Use strategy default"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
|
style="flex-basis: 100%"
|
||||||
:disabled="btStore.stakeAmountUnlimited"
|
:disabled="btStore.stakeAmountUnlimited"
|
||||||
></b-form-input>
|
></b-form-input>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,6 +90,7 @@
|
||||||
label="Enable Protections:"
|
label="Enable Protections:"
|
||||||
label-align-sm="right"
|
label-align-sm="right"
|
||||||
label-for="enable-protections"
|
label-for="enable-protections"
|
||||||
|
class="align-items-center"
|
||||||
>
|
>
|
||||||
<b-form-checkbox
|
<b-form-checkbox
|
||||||
id="enable-protections"
|
id="enable-protections"
|
||||||
|
@ -102,6 +103,7 @@
|
||||||
label="Cache Backtest results:"
|
label="Cache Backtest results:"
|
||||||
label-align-sm="right"
|
label-align-sm="right"
|
||||||
label-for="enable-cache"
|
label-for="enable-cache"
|
||||||
|
class="align-items-center"
|
||||||
>
|
>
|
||||||
<b-form-checkbox id="enable-cache" v-model="btStore.allowCache"></b-form-checkbox>
|
<b-form-checkbox id="enable-cache" v-model="btStore.allowCache"></b-form-checkbox>
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
|
@ -111,6 +113,7 @@
|
||||||
label="Enable FreqAI:"
|
label="Enable FreqAI:"
|
||||||
label-align-sm="right"
|
label-align-sm="right"
|
||||||
label-for="enable-freqai"
|
label-for="enable-freqai"
|
||||||
|
class="align-items-center"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-form-group v-if="backtestMode" label-for="trade-filter" class="mb-2">
|
<b-form-group v-if="backtestMode" label-for="trade-filter" class="mb-2 me-5">
|
||||||
<b-form-input id="trade-filter" v-model="filterText" type="text" placeholder="Filter" />
|
<b-form-input id="trade-filter" v-model="filterText" type="text" placeholder="Filter" />
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
<b-list-group>
|
<b-list-group>
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
<b-button
|
<b-button
|
||||||
size="sm"
|
size="sm"
|
||||||
class="ms-auto"
|
class="ms-auto mt-auto"
|
||||||
variant="outline-secondary"
|
variant="outline-secondary"
|
||||||
@click="ordersVisible[i] = !ordersVisible[i]"
|
@click="ordersVisible[i] = !ordersVisible[i]"
|
||||||
><i-mdi-chevron-right v-if="!ordersVisible[i]" width="24" height="24" />
|
><i-mdi-chevron-right v-if="!ordersVisible[i]" width="24" height="24" />
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
class="mx-1 flex-samesize-items"
|
class="mx-1 flex-samesize-items"
|
||||||
value="historicResults"
|
value="historicResults"
|
||||||
:disabled="!botStore.activeBot.canRunBacktest"
|
:disabled="!botStore.activeBot.canRunBacktest"
|
||||||
>Load Results</b-form-radio
|
><i-mdi-cloud-download class="me-2" />Load Results</b-form-radio
|
||||||
>
|
>
|
||||||
<b-form-radio
|
<b-form-radio
|
||||||
v-model="btFormMode"
|
v-model="btFormMode"
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
class="mx-1 flex-samesize-items"
|
class="mx-1 flex-samesize-items"
|
||||||
value="run"
|
value="run"
|
||||||
:disabled="!botStore.activeBot.canRunBacktest"
|
:disabled="!botStore.activeBot.canRunBacktest"
|
||||||
>Run backtest</b-form-radio
|
><i-mdi-run-fast class="me-2" />Run backtest</b-form-radio
|
||||||
>
|
>
|
||||||
<b-form-radio
|
<b-form-radio
|
||||||
id="bt-analyze-btn"
|
id="bt-analyze-btn"
|
||||||
|
@ -37,7 +37,17 @@
|
||||||
class="mx-1 flex-samesize-items"
|
class="mx-1 flex-samesize-items"
|
||||||
value="results"
|
value="results"
|
||||||
:disabled="!hasBacktestResult"
|
:disabled="!hasBacktestResult"
|
||||||
>Analyze result</b-form-radio
|
><i-mdi-table-eye class="me-2" />Analyze result</b-form-radio
|
||||||
|
>
|
||||||
|
<b-form-radio
|
||||||
|
v-if="hasMultiBacktestResult"
|
||||||
|
v-model="btFormMode"
|
||||||
|
name="bt-form-radios"
|
||||||
|
button
|
||||||
|
class="mx-1 flex-samesize-items"
|
||||||
|
value="compare-results"
|
||||||
|
:disabled="!hasMultiBacktestResult"
|
||||||
|
><i-mdi-compare-horizontal class="me-2" />Compare results</b-form-radio
|
||||||
>
|
>
|
||||||
<b-form-radio
|
<b-form-radio
|
||||||
v-model="btFormMode"
|
v-model="btFormMode"
|
||||||
|
@ -46,7 +56,7 @@
|
||||||
class="mx-1 flex-samesize-items"
|
class="mx-1 flex-samesize-items"
|
||||||
value="visualize-summary"
|
value="visualize-summary"
|
||||||
:disabled="!hasBacktestResult"
|
:disabled="!hasBacktestResult"
|
||||||
>Visualize summary</b-form-radio
|
><i-mdi-chart-bell-curve-cumulative class="me-2" />Visualize summary</b-form-radio
|
||||||
>
|
>
|
||||||
<b-form-radio
|
<b-form-radio
|
||||||
v-model="btFormMode"
|
v-model="btFormMode"
|
||||||
|
@ -55,7 +65,7 @@
|
||||||
class="mx-1 flex-samesize-items"
|
class="mx-1 flex-samesize-items"
|
||||||
value="visualize"
|
value="visualize"
|
||||||
:disabled="!hasBacktestResult"
|
:disabled="!hasBacktestResult"
|
||||||
>Visualize result</b-form-radio
|
><i-mdi-chart-timeline-variant-shimmer class="me-2" />Visualize result</b-form-radio
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<small v-show="botStore.activeBot.backtestRunning" class="text-end bt-running-label"
|
<small v-show="botStore.activeBot.backtestRunning" class="text-end bt-running-label"
|
||||||
|
@ -113,6 +123,12 @@
|
||||||
class="flex-fill"
|
class="flex-fill"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<BacktestResultComparison
|
||||||
|
v-if="hasBacktestResult && btFormMode === 'compare-results'"
|
||||||
|
:backtest-results="botStore.activeBot.backtestHistory"
|
||||||
|
class="flex-fill"
|
||||||
|
/>
|
||||||
|
|
||||||
<BacktestGraphs
|
<BacktestGraphs
|
||||||
v-if="hasBacktestResult && btFormMode === 'visualize-summary'"
|
v-if="hasBacktestResult && btFormMode === 'visualize-summary'"
|
||||||
:trades="botStore.activeBot.selectedBacktestResult.trades"
|
:trades="botStore.activeBot.selectedBacktestResult.trades"
|
||||||
|
@ -141,6 +157,7 @@ import BacktestHistoryLoad from '@/components/ftbot/BacktestHistoryLoad.vue';
|
||||||
import BacktestResultChart from '@/components/ftbot/BacktestResultChart.vue';
|
import BacktestResultChart from '@/components/ftbot/BacktestResultChart.vue';
|
||||||
import BacktestResultSelect from '@/components/ftbot/BacktestResultSelect.vue';
|
import BacktestResultSelect from '@/components/ftbot/BacktestResultSelect.vue';
|
||||||
import BacktestResultAnalysis from '@/components/ftbot/BacktestResultAnalysis.vue';
|
import BacktestResultAnalysis from '@/components/ftbot/BacktestResultAnalysis.vue';
|
||||||
|
import BacktestResultComparison from '@/components/ftbot/BacktestResultComparison.vue';
|
||||||
import BacktestRun from '@/components/ftbot/BacktestRun.vue';
|
import BacktestRun from '@/components/ftbot/BacktestRun.vue';
|
||||||
|
|
||||||
import { formatPercent } from '@/shared/formatters';
|
import { formatPercent } from '@/shared/formatters';
|
||||||
|
@ -153,6 +170,7 @@ enum BtRunModes {
|
||||||
results = 'results',
|
results = 'results',
|
||||||
visualize = 'visualize',
|
visualize = 'visualize',
|
||||||
visualizesummary = 'visualize-summary',
|
visualizesummary = 'visualize-summary',
|
||||||
|
compareresults = 'compare-results',
|
||||||
historicresults = 'historicResults',
|
historicresults = 'historicResults',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +182,12 @@ const hasBacktestResult = computed(() =>
|
||||||
? Object.keys(botStore.activeBot.backtestHistory).length !== 0
|
? Object.keys(botStore.activeBot.backtestHistory).length !== 0
|
||||||
: false,
|
: false,
|
||||||
);
|
);
|
||||||
|
const hasMultiBacktestResult = computed(() =>
|
||||||
|
botStore.activeBot.backtestHistory
|
||||||
|
? Object.keys(botStore.activeBot.backtestHistory).length > 1
|
||||||
|
: false,
|
||||||
|
);
|
||||||
|
|
||||||
const timeframe = computed((): string => {
|
const timeframe = computed((): string => {
|
||||||
try {
|
try {
|
||||||
return botStore.activeBot.selectedBacktestResult.timeframe;
|
return botStore.activeBot.selectedBacktestResult.timeframe;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user