Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backtest comparison view, allowing the comparison of multiple strategies #1550

Merged
merged 5 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions src/components/ftbot/BacktestResultComparison.vue
Original file line number Diff line number Diff line change
@@ -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>
19 changes: 11 additions & 8 deletions src/components/ftbot/BacktestRun.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<b-form-input
id="starting-capital"
v-model="btStore.startingCapital"
placeholder="Use config default"
type="number"
step="0.001"
></b-form-input>
Expand All @@ -66,20 +67,19 @@
label-align-sm="right"
label-for="stake-amount"
>
<div class="d-flex">
<b-form-checkbox
id="stake-amount-bool"
v-model="btStore.stakeAmountUnlimited"
class="col-md-6"
>Unlimited stake</b-form-checkbox
>

<div class="d-flex align-items-center">
<div style="flex-basis: 100%" class="d-flex">
<b-form-checkbox id="stake-amount-bool" v-model="btStore.stakeAmountUnlimited"
>Unlimited stake</b-form-checkbox
>
</div>
<b-form-input
id="stake-amount"
v-model="btStore.stakeAmount"
type="number"
placeholder="Use strategy default"
step="0.01"
style="flex-basis: 100%"
:disabled="btStore.stakeAmountUnlimited"
></b-form-input>
</div>
Expand All @@ -90,6 +90,7 @@
label="Enable Protections:"
label-align-sm="right"
label-for="enable-protections"
class="align-items-center"
>
<b-form-checkbox
id="enable-protections"
Expand All @@ -102,6 +103,7 @@
label="Cache Backtest results:"
label-align-sm="right"
label-for="enable-cache"
class="align-items-center"
>
<b-form-checkbox id="enable-cache" v-model="btStore.allowCache"></b-form-checkbox>
</b-form-group>
Expand All @@ -111,6 +113,7 @@
label="Enable FreqAI:"
label-align-sm="right"
label-for="enable-freqai"
class="align-items-center"
>
<template #label>
<div class="d-flex justify-content-center">
Expand Down
2 changes: 1 addition & 1 deletion src/components/ftbot/PairSummary.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<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-group>
<b-list-group>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ftbot/TradeListNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</div>
<b-button
size="sm"
class="ms-auto"
class="ms-auto mt-auto"
variant="outline-secondary"
@click="ordersVisible[i] = !ordersVisible[i]"
><i-mdi-chevron-right v-if="!ordersVisible[i]" width="24" height="24" />
Expand Down
34 changes: 29 additions & 5 deletions src/views/BacktestingView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class="mx-1 flex-samesize-items"
value="historicResults"
:disabled="!botStore.activeBot.canRunBacktest"
>Load Results</b-form-radio
><i-mdi-cloud-download class="me-2" />Load Results</b-form-radio
>
<b-form-radio
v-model="btFormMode"
Expand All @@ -27,7 +27,7 @@
class="mx-1 flex-samesize-items"
value="run"
:disabled="!botStore.activeBot.canRunBacktest"
>Run backtest</b-form-radio
><i-mdi-run-fast class="me-2" />Run backtest</b-form-radio
>
<b-form-radio
id="bt-analyze-btn"
Expand All @@ -37,7 +37,17 @@
class="mx-1 flex-samesize-items"
value="results"
: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
v-model="btFormMode"
Expand All @@ -46,7 +56,7 @@
class="mx-1 flex-samesize-items"
value="visualize-summary"
:disabled="!hasBacktestResult"
>Visualize summary</b-form-radio
><i-mdi-chart-bell-curve-cumulative class="me-2" />Visualize summary</b-form-radio
>
<b-form-radio
v-model="btFormMode"
Expand All @@ -55,7 +65,7 @@
class="mx-1 flex-samesize-items"
value="visualize"
:disabled="!hasBacktestResult"
>Visualize result</b-form-radio
><i-mdi-chart-timeline-variant-shimmer class="me-2" />Visualize result</b-form-radio
>
</div>
<small v-show="botStore.activeBot.backtestRunning" class="text-end bt-running-label"
Expand Down Expand Up @@ -113,6 +123,12 @@
class="flex-fill"
/>

<BacktestResultComparison
v-if="hasBacktestResult && btFormMode === 'compare-results'"
:backtest-results="botStore.activeBot.backtestHistory"
class="flex-fill"
/>

<BacktestGraphs
v-if="hasBacktestResult && btFormMode === 'visualize-summary'"
:trades="botStore.activeBot.selectedBacktestResult.trades"
Expand Down Expand Up @@ -141,6 +157,7 @@ import BacktestHistoryLoad from '@/components/ftbot/BacktestHistoryLoad.vue';
import BacktestResultChart from '@/components/ftbot/BacktestResultChart.vue';
import BacktestResultSelect from '@/components/ftbot/BacktestResultSelect.vue';
import BacktestResultAnalysis from '@/components/ftbot/BacktestResultAnalysis.vue';
import BacktestResultComparison from '@/components/ftbot/BacktestResultComparison.vue';
import BacktestRun from '@/components/ftbot/BacktestRun.vue';

import { formatPercent } from '@/shared/formatters';
Expand All @@ -153,6 +170,7 @@ enum BtRunModes {
results = 'results',
visualize = 'visualize',
visualizesummary = 'visualize-summary',
compareresults = 'compare-results',
historicresults = 'historicResults',
}

Expand All @@ -164,6 +182,12 @@ const hasBacktestResult = computed(() =>
? Object.keys(botStore.activeBot.backtestHistory).length !== 0
: false,
);
const hasMultiBacktestResult = computed(() =>
botStore.activeBot.backtestHistory
? Object.keys(botStore.activeBot.backtestHistory).length > 1
: false,
);

const timeframe = computed((): string => {
try {
return botStore.activeBot.selectedBacktestResult.timeframe;
Expand Down