2020-07-26 17:35:56 +00:00
|
|
|
<template>
|
|
|
|
<div class="container">
|
2021-01-19 21:50:51 +00:00
|
|
|
<div>
|
2021-03-10 15:09:55 +00:00
|
|
|
<h3>Backtest-result for {{ backtestResult.strategy_name }}</h3>
|
2020-07-26 17:35:56 +00:00
|
|
|
</div>
|
|
|
|
<div class="container">
|
2021-01-19 21:50:51 +00:00
|
|
|
<div class="row">
|
|
|
|
<div class="col-md-6">
|
|
|
|
<b-card header="Strategy settings">
|
|
|
|
<b-table
|
|
|
|
class="table-sm"
|
|
|
|
:items="backtestResultSettings"
|
|
|
|
:fields="backtestsettingFields"
|
|
|
|
>
|
|
|
|
</b-table>
|
|
|
|
</b-card>
|
|
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
|
|
<b-card header="Metrics">
|
|
|
|
<b-table class="table-sm" :items="backtestResultStats" :fields="backtestResultFields">
|
|
|
|
</b-table>
|
|
|
|
</b-card>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2020-07-26 17:36:47 +00:00
|
|
|
<b-card header="Results per Sell-reason" class="mt-2">
|
|
|
|
<b-table
|
|
|
|
class="table-sm"
|
|
|
|
:items="backtestResult.sell_reason_summary"
|
|
|
|
:fields="perSellReason"
|
|
|
|
>
|
|
|
|
</b-table>
|
|
|
|
</b-card>
|
2021-01-06 19:25:38 +00:00
|
|
|
<b-card header="Results per pair" class="mt-2">
|
|
|
|
<b-table class="table-sm" :items="backtestResult.results_per_pair" :fields="perPairFields">
|
|
|
|
</b-table>
|
|
|
|
</b-card>
|
2020-07-26 17:36:47 +00:00
|
|
|
|
2020-08-08 18:22:05 +00:00
|
|
|
<TradeList
|
|
|
|
class="trade-history mt-2"
|
|
|
|
:trades="backtestResult.trades"
|
2020-08-18 17:45:58 +00:00
|
|
|
profit-column="profit_percent"
|
2020-08-08 18:22:05 +00:00
|
|
|
/>
|
2020-07-26 17:35:56 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import TradeList from '@/components/ftbot/TradeList.vue';
|
|
|
|
import { Component, Vue, Prop } from 'vue-property-decorator';
|
2021-01-21 06:47:51 +00:00
|
|
|
import { StrategyBacktestResult, Trade } from '@/types';
|
2020-07-26 17:35:56 +00:00
|
|
|
|
2020-09-12 17:21:35 +00:00
|
|
|
import {
|
|
|
|
timestampms,
|
|
|
|
formatPercent,
|
|
|
|
formatPrice,
|
|
|
|
humanizeDurationFromSeconds,
|
|
|
|
} from '@/shared/formatters';
|
2020-07-26 17:35:56 +00:00
|
|
|
|
|
|
|
@Component({
|
|
|
|
components: { TradeList },
|
|
|
|
})
|
|
|
|
export default class BacktestResultView extends Vue {
|
|
|
|
@Prop({ required: true }) readonly backtestResult!: StrategyBacktestResult;
|
|
|
|
|
|
|
|
get hasBacktestResult() {
|
|
|
|
return !!this.backtestResult;
|
|
|
|
}
|
|
|
|
|
2021-01-21 06:47:51 +00:00
|
|
|
getSortedTrades(backtestResult: StrategyBacktestResult): Trade[] {
|
|
|
|
const sortedTrades = backtestResult.trades
|
|
|
|
.slice()
|
|
|
|
.sort((a, b) => a.profit_ratio - b.profit_ratio);
|
|
|
|
return sortedTrades;
|
|
|
|
}
|
|
|
|
|
2021-02-28 08:53:51 +00:00
|
|
|
formatPriceStake(price) {
|
|
|
|
return `${formatPrice(price, this.backtestResult.stake_currency_decimals)} ${
|
|
|
|
this.backtestResult.stake_currency
|
|
|
|
}`;
|
|
|
|
}
|
|
|
|
|
2021-01-21 06:47:51 +00:00
|
|
|
get bestPair(): string {
|
|
|
|
const trades = this.getSortedTrades(this.backtestResult);
|
|
|
|
const value = trades[trades.length - 1];
|
|
|
|
return `${value.pair} ${formatPercent(value.profit_ratio, 2)}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
get worstPair(): string {
|
|
|
|
const trades = this.getSortedTrades(this.backtestResult);
|
|
|
|
const value = trades[0];
|
|
|
|
return `${value.pair} ${formatPercent(value.profit_ratio, 2)}`;
|
|
|
|
}
|
|
|
|
|
2020-07-26 17:35:56 +00:00
|
|
|
get backtestResultStats() {
|
|
|
|
// Transpose Result into readable format
|
|
|
|
return [
|
|
|
|
{ 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 },
|
2020-09-12 17:21:35 +00:00
|
|
|
{
|
|
|
|
metric: 'Total Profit',
|
2021-02-28 08:53:51 +00:00
|
|
|
value: `${formatPercent(this.backtestResult.profit_total)} | ${this.formatPriceStake(
|
2020-09-12 17:21:35 +00:00
|
|
|
this.backtestResult.profit_total_abs,
|
2021-02-28 08:53:51 +00:00
|
|
|
)}`,
|
2020-09-12 17:21:35 +00:00
|
|
|
},
|
2020-07-26 17:35:56 +00:00
|
|
|
{ metric: 'Trades per day', value: this.backtestResult.trades_per_day },
|
2020-12-05 15:22:41 +00:00
|
|
|
|
2021-03-08 18:39:15 +00:00
|
|
|
{
|
|
|
|
metric: 'Best day',
|
|
|
|
value: `${formatPercent(
|
|
|
|
this.backtestResult.backtest_best_day,
|
|
|
|
2,
|
|
|
|
)} | ${this.formatPriceStake(this.backtestResult.backtest_best_day_abs)}`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
metric: 'Worst day',
|
|
|
|
value: `${formatPercent(
|
|
|
|
this.backtestResult.backtest_worst_day,
|
|
|
|
2,
|
|
|
|
)} | ${this.formatPriceStake(this.backtestResult.backtest_worst_day_abs)}`,
|
|
|
|
},
|
2021-01-21 06:47:51 +00:00
|
|
|
|
2021-01-19 21:50:51 +00:00
|
|
|
{
|
|
|
|
metric: 'Win/Draw/Loss',
|
|
|
|
value: `${
|
|
|
|
this.backtestResult.results_per_pair[this.backtestResult.results_per_pair.length - 1].wins
|
|
|
|
} / ${
|
|
|
|
this.backtestResult.results_per_pair[this.backtestResult.results_per_pair.length - 1]
|
|
|
|
.draws
|
|
|
|
} / ${
|
|
|
|
this.backtestResult.results_per_pair[this.backtestResult.results_per_pair.length - 1]
|
|
|
|
.losses
|
|
|
|
}`,
|
|
|
|
},
|
2020-09-12 17:21:35 +00:00
|
|
|
{
|
|
|
|
metric: 'Days win/draw/loss',
|
|
|
|
value: `${this.backtestResult.winning_days} / ${this.backtestResult.draw_days} / ${this.backtestResult.losing_days}`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
metric: 'Avg. Duration winners',
|
|
|
|
value: humanizeDurationFromSeconds(this.backtestResult.winner_holding_avg),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
metric: 'Avg. Duration Losers',
|
|
|
|
value: humanizeDurationFromSeconds(this.backtestResult.loser_holding_avg),
|
|
|
|
},
|
|
|
|
{ metric: 'Max Drawdown', value: formatPercent(this.backtestResult.max_drawdown) },
|
2021-02-28 08:53:51 +00:00
|
|
|
{
|
|
|
|
metric: 'Max Drawdown ABS',
|
|
|
|
value: this.formatPriceStake(this.backtestResult.max_drawdown_abs),
|
|
|
|
},
|
2020-07-26 17:35:56 +00:00
|
|
|
{ metric: 'Drawdown start', value: this.backtestResult.drawdown_start },
|
|
|
|
{ metric: 'Drawdown end', value: this.backtestResult.drawdown_end },
|
2021-02-28 08:53:51 +00:00
|
|
|
{ metric: 'Min balance', value: this.formatPriceStake(this.backtestResult.csum_min) },
|
|
|
|
{ metric: 'Max balance', value: this.formatPriceStake(this.backtestResult.csum_max) },
|
2020-09-12 17:21:35 +00:00
|
|
|
{ metric: 'Market change', value: formatPercent(this.backtestResult.market_change) },
|
2021-01-16 10:05:44 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
metric: 'Best Pair',
|
|
|
|
value: `${this.backtestResult.best_pair.key} ${formatPercent(
|
|
|
|
this.backtestResult.best_pair.profit_sum,
|
|
|
|
)}`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
metric: 'Worst Pair',
|
|
|
|
value: `${this.backtestResult.worst_pair.key} ${formatPercent(
|
|
|
|
this.backtestResult.worst_pair.profit_sum,
|
|
|
|
)}`,
|
|
|
|
},
|
2021-01-21 06:47:51 +00:00
|
|
|
{ metric: 'Best single Trade', value: this.bestPair },
|
|
|
|
{ metric: 'Worst single Trade', value: this.worstPair },
|
2020-07-26 17:35:56 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2021-01-19 21:50:51 +00:00
|
|
|
get backtestResultSettings() {
|
|
|
|
// Transpose Result into readable format
|
|
|
|
return [
|
|
|
|
{ setting: 'Backtesting from', value: timestampms(this.backtestResult.backtest_start_ts) },
|
|
|
|
{ setting: 'Backtesting to', value: timestampms(this.backtestResult.backtest_end_ts) },
|
|
|
|
{ setting: 'Max open trades', value: this.backtestResult.max_open_trades },
|
|
|
|
{ setting: 'Timeframe', value: this.backtestResult.timeframe },
|
|
|
|
{ setting: 'Timerange', value: this.backtestResult.timerange },
|
|
|
|
{ setting: 'Stoploss', value: formatPercent(this.backtestResult.stoploss, 2) },
|
|
|
|
{ setting: 'Trailing Stoploss', value: this.backtestResult.trailing_stop },
|
|
|
|
{
|
|
|
|
setting: 'Trail only when offset is reached',
|
|
|
|
value: this.backtestResult.trailing_only_offset_is_reached,
|
|
|
|
},
|
|
|
|
{ setting: 'Trailing Stop positive', value: this.backtestResult.trailing_stop_positive },
|
|
|
|
{
|
|
|
|
setting: 'Trailing stop positive offset',
|
|
|
|
value: this.backtestResult.trailing_stop_positive_offset,
|
|
|
|
},
|
|
|
|
{ setting: 'Custom Stoploss', value: this.backtestResult.use_custom_stoploss },
|
|
|
|
{ setting: 'ROI', value: this.backtestResult.minimal_roi },
|
|
|
|
{ setting: 'Use Sell Signal', value: this.backtestResult.use_sell_signal },
|
|
|
|
{ setting: 'Sell profit only', value: this.backtestResult.sell_profit_only },
|
|
|
|
{ setting: 'Sell profit offset', value: this.backtestResult.sell_profit_offset },
|
|
|
|
{ setting: 'Enable protections', value: this.backtestResult.enable_protections },
|
2021-02-28 08:53:51 +00:00
|
|
|
{
|
|
|
|
setting: 'Starting balance',
|
|
|
|
value: this.formatPriceStake(this.backtestResult.starting_balance),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
setting: 'Final balance',
|
|
|
|
value: this.formatPriceStake(this.backtestResult.final_balance),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
setting: 'Avg. stake amount',
|
|
|
|
value: this.formatPriceStake(this.backtestResult.avg_stake_amount),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
setting: 'Total trade volume',
|
|
|
|
value: this.formatPriceStake(this.backtestResult.total_volume),
|
|
|
|
},
|
2021-01-19 21:50:51 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2020-07-26 17:36:47 +00:00
|
|
|
get perPairFields() {
|
|
|
|
return [
|
|
|
|
{ key: 'key', label: 'Pair' },
|
|
|
|
{ key: 'trades', label: 'Buys' },
|
|
|
|
{ key: 'profit_mean', label: 'Avg Profit %', formatter: (value) => formatPercent(value, 2) },
|
|
|
|
{ key: 'profit_sum', label: 'Cum Profit %', formatter: (value) => formatPercent(value, 2) },
|
2020-09-12 17:21:35 +00:00
|
|
|
{
|
|
|
|
key: 'profit_total_abs',
|
|
|
|
label: `Tot Profit ${this.backtestResult.stake_currency}`,
|
|
|
|
formatter: (value) => formatPrice(value),
|
|
|
|
},
|
2020-07-26 17:36:47 +00:00
|
|
|
{
|
2020-12-05 15:22:41 +00:00
|
|
|
key: 'profit_total',
|
2020-07-26 17:36:47 +00:00
|
|
|
label: 'Tot Profit %',
|
|
|
|
formatter: (value) => formatPercent(value, 2),
|
|
|
|
},
|
|
|
|
{ key: 'duration_avg', label: 'Avg Duration' },
|
|
|
|
{ key: 'wins', label: 'Wins' },
|
|
|
|
{ key: 'draws', label: 'Draws' },
|
|
|
|
{ key: 'losses', label: 'Losses' },
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
get perSellReason() {
|
|
|
|
return [
|
|
|
|
{ key: 'sell_reason', label: 'Sell Reason' },
|
|
|
|
{ key: 'trades', label: 'Buys' },
|
|
|
|
{ key: 'profit_mean', label: 'Avg Profit %', formatter: (value) => formatPercent(value, 2) },
|
|
|
|
{ key: 'profit_sum', label: 'Cum Profit %', formatter: (value) => formatPercent(value, 2) },
|
|
|
|
{ key: 'profit_total_abs', label: `Tot Profit ${this.backtestResult.stake_currency}` },
|
|
|
|
{
|
2020-09-16 18:28:26 +00:00
|
|
|
key: 'profit_total',
|
2020-07-26 17:36:47 +00:00
|
|
|
label: 'Tot Profit %',
|
|
|
|
formatter: (value) => formatPercent(value, 2),
|
|
|
|
},
|
|
|
|
{ key: 'wins', label: 'Wins' },
|
|
|
|
{ key: 'draws', label: 'Draws' },
|
|
|
|
{ key: 'losses', label: 'Losses' },
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2020-07-26 17:35:56 +00:00
|
|
|
backtestResultFields: Array<Record<string, string>> = [
|
|
|
|
{ key: 'metric', label: 'Metric' },
|
|
|
|
{ key: 'value', label: 'Value' },
|
|
|
|
];
|
2021-01-19 21:50:51 +00:00
|
|
|
|
|
|
|
backtestsettingFields: Array<Record<string, string>> = [
|
|
|
|
{ key: 'setting', label: 'Setting' },
|
|
|
|
{ key: 'value', label: 'Value' },
|
|
|
|
];
|
2020-07-26 17:35:56 +00:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style></style>
|