mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-13 03:33:50 +00:00
Backtesting enhancements
This commit is contained in:
parent
6f14b7a5bf
commit
9eddc34057
62
src/components/ftbot/BacktestResultView.vue
Normal file
62
src/components/ftbot/BacktestResultView.vue
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<h2>BacktestResult for {{ strategy }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">Backtest days {{ backtestResult.backtest_days }}</div>
|
||||||
|
|
||||||
|
<b-table class="table-sm" :items="backtestResultStats" :fields="backtestResultFields">
|
||||||
|
</b-table>
|
||||||
|
<TradeList class="trade-history" :trades="backtestResult.trades" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import TradeList from '@/components/ftbot/TradeList.vue';
|
||||||
|
import { Component, Vue, Prop } from 'vue-property-decorator';
|
||||||
|
import { StrategyBacktestResult } from '@/types';
|
||||||
|
|
||||||
|
import { timestampms } from '@/shared/formatters';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: { TradeList },
|
||||||
|
})
|
||||||
|
export default class BacktestResultView extends Vue {
|
||||||
|
@Prop({ required: true }) readonly strategy!: string;
|
||||||
|
|
||||||
|
@Prop({ required: true }) readonly backtestResult!: StrategyBacktestResult;
|
||||||
|
|
||||||
|
get hasBacktestResult() {
|
||||||
|
return !!this.backtestResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
get backtestResultStats() {
|
||||||
|
// Transpose Result into readable format
|
||||||
|
return [
|
||||||
|
{ metric: 'Backtesting from', value: timestampms(this.backtestResult.backtest_start_ts) },
|
||||||
|
{ metric: 'Backtesting to', value: timestampms(this.backtestResult.backtest_end_ts) },
|
||||||
|
{ metric: 'Total trades', value: this.backtestResult.total_trades },
|
||||||
|
// { metric: 'First trade', value: this.backtestResult.backtest_fi },
|
||||||
|
// { metric: 'First trade Pair', value: this.backtestResult.backtest_best_day },
|
||||||
|
{ metric: 'Trades per day', value: this.backtestResult.trades_per_day },
|
||||||
|
{ metric: 'Best day', value: this.backtestResult.backtest_best_day },
|
||||||
|
{ metric: 'Wrost day', value: this.backtestResult.backtest_worst_day },
|
||||||
|
{ metric: 'Avg. Duration winners', value: this.backtestResult.winner_holding_avg },
|
||||||
|
{ metric: 'Avg. Duration Losers', value: this.backtestResult.loser_holding_avg },
|
||||||
|
{ metric: 'Max Drawdown', value: this.backtestResult.max_drawdown },
|
||||||
|
{ metric: 'Drawdown start', value: this.backtestResult.drawdown_start },
|
||||||
|
{ metric: 'Drawdown end', value: this.backtestResult.drawdown_end },
|
||||||
|
{ metric: 'Market chnage', value: this.backtestResult.market_change },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
backtestResultFields: Array<Record<string, string>> = [
|
||||||
|
{ key: 'metric', label: 'Metric' },
|
||||||
|
{ key: 'value', label: 'Value' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
|
@ -5,6 +5,64 @@ export interface BacktestPayload {
|
||||||
timerange: string;
|
timerange: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BacktestResult {
|
export interface PairResults {
|
||||||
trades: Trade[];
|
draws: number;
|
||||||
|
duration_avg: string;
|
||||||
|
key: string;
|
||||||
|
losses: number;
|
||||||
|
profit_mean: number;
|
||||||
|
profit_mean_pct: number;
|
||||||
|
profit_sum: number;
|
||||||
|
profit_sum_pct: number;
|
||||||
|
profit_total_abs: number;
|
||||||
|
profit_total_pct: number;
|
||||||
|
trades: number;
|
||||||
|
wins: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SellReasonResults {
|
||||||
|
draws: number;
|
||||||
|
losses: number;
|
||||||
|
profit_mean: number;
|
||||||
|
profit_mean_pct: number;
|
||||||
|
profit_sum: number;
|
||||||
|
profit_sum_pct: number;
|
||||||
|
profit_total_abs: number;
|
||||||
|
profit_total_pct: number;
|
||||||
|
trades: number;
|
||||||
|
wins: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StrategyBacktestResult {
|
||||||
|
trades: Trade[];
|
||||||
|
left_open_trades: Trade[];
|
||||||
|
backtest_best_day: number;
|
||||||
|
backtest_days: number;
|
||||||
|
backtest_end: string;
|
||||||
|
backtest_end_ts: number;
|
||||||
|
backtest_start: string;
|
||||||
|
backtest_start_ts: number;
|
||||||
|
backtest_worst_day: number;
|
||||||
|
draw_days: number;
|
||||||
|
drawdown_end: string;
|
||||||
|
drawdown_end_ts: number;
|
||||||
|
drawdown_start: string;
|
||||||
|
drawdown_start_ts: number;
|
||||||
|
loser_holding_avg: number;
|
||||||
|
losing_days: number;
|
||||||
|
market_change: number;
|
||||||
|
max_drawdown: number;
|
||||||
|
pairlist: string[];
|
||||||
|
results_per_pair: Array<PairResults>;
|
||||||
|
sell_reason_summary: Array<SellReasonResults>;
|
||||||
|
stake_amount: number;
|
||||||
|
total_trades: number;
|
||||||
|
trades_per_day: number;
|
||||||
|
winner_holding_avg: number;
|
||||||
|
winning_days: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BacktestResult {
|
||||||
|
strategy: Record<string, StrategyBacktestResult>;
|
||||||
|
strategy_comparison: Array<Record<string, string | number>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,46 +3,65 @@
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<TimeRangeSelect v-model="timerange"></TimeRangeSelect>
|
<TimeRangeSelect v-model="timerange"></TimeRangeSelect>
|
||||||
</div>
|
</div>
|
||||||
<b-button variant="primary" :disabled="backtestRunning" @click="clickBacktest">
|
<div class="row">
|
||||||
Start backtest
|
<b-button variant="primary" :disabled="backtestRunning" @click="clickBacktest">
|
||||||
</b-button>
|
Start backtest
|
||||||
|
</b-button>
|
||||||
|
<b-button variant="primary" :disabled="backtestRunning" @click="pollBacktest">
|
||||||
|
Load backtest result
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
<div v-if="hasBacktestResult" class="text-center w-100 mt-5">
|
||||||
|
<BacktestResultView
|
||||||
|
:strategy="strategy"
|
||||||
|
:backtest-result="backtestResult.strategy ? backtestResult.strategy[strategy] : {}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue, Watch } from 'vue-property-decorator';
|
import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||||
import { namespace } from 'vuex-class';
|
import { namespace } from 'vuex-class';
|
||||||
import CandleChart from '@/components/charts/CandleChart.vue';
|
|
||||||
import PlotConfigurator from '@/components/charts/PlotConfigurator.vue';
|
|
||||||
import TimeRangeSelect from '@/components/ftbot/TimeRangeSelect.vue';
|
import TimeRangeSelect from '@/components/ftbot/TimeRangeSelect.vue';
|
||||||
import { BacktestPayload } from '@/types';
|
import BacktestResultView from '@/components/ftbot/BacktestResultView.vue';
|
||||||
|
|
||||||
|
import { BacktestPayload, BacktestResult } from '@/types';
|
||||||
|
|
||||||
const ftbot = namespace('ftbot');
|
const ftbot = namespace('ftbot');
|
||||||
@Component({
|
@Component({
|
||||||
components: { CandleChart, PlotConfigurator, TimeRangeSelect },
|
components: { BacktestResultView, TimeRangeSelect },
|
||||||
})
|
})
|
||||||
export default class Graphs extends Vue {
|
export default class Backtesting extends Vue {
|
||||||
pair = 'XRP/USDT';
|
pair = 'XRP/USDT';
|
||||||
|
|
||||||
pollInterval: NodeJS.Timer | null = null;
|
pollInterval: number | null = null;
|
||||||
|
|
||||||
timeframe = '5m';
|
timeframe = '5m';
|
||||||
|
|
||||||
|
strategy = 'BinHV45';
|
||||||
|
|
||||||
timeframems = 300000;
|
timeframems = 300000;
|
||||||
|
|
||||||
@ftbot.State backtestRunning!: boolean;
|
@ftbot.State backtestRunning!: boolean;
|
||||||
|
|
||||||
|
@ftbot.State backtestResult!: BacktestResult;
|
||||||
|
|
||||||
timerange = '';
|
timerange = '';
|
||||||
|
|
||||||
@ftbot.Action
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
startBacktest!: (payload: BacktestPayload) => void;
|
@ftbot.Action startBacktest!: (payload: BacktestPayload) => void;
|
||||||
|
|
||||||
@ftbot.Action pollBacktest!: () => void;
|
@ftbot.Action pollBacktest!: () => void;
|
||||||
|
|
||||||
|
get hasBacktestResult() {
|
||||||
|
return Object.keys(this.backtestResult).length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
clickBacktest() {
|
clickBacktest() {
|
||||||
console.log('Backtesting');
|
console.log('Backtesting');
|
||||||
const btPayload: BacktestPayload = {
|
const btPayload: BacktestPayload = {
|
||||||
strategy: 'BinHV45',
|
strategy: this.strategy,
|
||||||
timerange: this.timerange,
|
timerange: this.timerange,
|
||||||
};
|
};
|
||||||
this.startBacktest(btPayload);
|
this.startBacktest(btPayload);
|
||||||
|
@ -51,7 +70,7 @@ export default class Graphs extends Vue {
|
||||||
@Watch('backtestRunning')
|
@Watch('backtestRunning')
|
||||||
backtestRunningChanged() {
|
backtestRunningChanged() {
|
||||||
if (this.backtestRunning === true) {
|
if (this.backtestRunning === true) {
|
||||||
this.pollInterval = setInterval(this.pollBacktest, 5000);
|
this.pollInterval = window.setInterval(this.pollBacktest, 1000);
|
||||||
} else if (this.pollInterval) {
|
} else if (this.pollInterval) {
|
||||||
clearInterval(this.pollInterval);
|
clearInterval(this.pollInterval);
|
||||||
this.pollInterval = null;
|
this.pollInterval = null;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user