composition: migrate remaining components

This commit is contained in:
Matthias 2022-04-21 06:37:57 +02:00
parent 2baabf7f04
commit e969cf83a8
6 changed files with 978 additions and 947 deletions

View File

@ -67,7 +67,7 @@ export default defineComponent({
get() { get() {
return botStore.botStores[props.bot.botId].autoRefresh; return botStore.botStores[props.bot.botId].autoRefresh;
}, },
set(_) { set() {
// pass // pass
}, },
}); });

File diff suppressed because it is too large Load Diff

View File

@ -103,7 +103,7 @@ export default defineComponent({
name: 'CandleChartContainer', name: 'CandleChartContainer',
components: { CandleChart, PlotConfigurator, vSelect }, components: { CandleChart, PlotConfigurator, vSelect },
props: { props: {
trades: { required: false, default: [], type: Array as () => Trade[] }, trades: { required: false, default: () => [], type: Array as () => Trade[] },
availablePairs: { required: true, type: Array as () => string[] }, availablePairs: { required: true, type: Array as () => string[] },
timeframe: { required: true, type: String }, timeframe: { required: true, type: String },
historicView: { required: false, default: false, type: Boolean }, historicView: { required: false, default: false, type: Boolean },

View File

@ -18,7 +18,7 @@ import {
} from 'echarts/components'; } from 'echarts/components';
import { ClosedTrade, CumProfitData, CumProfitDataPerDate } from '@/types'; import { ClosedTrade, CumProfitData, CumProfitDataPerDate } from '@/types';
import { defineComponent, ref, computed } from '@vue/composition-api'; import { defineComponent, ref, computed, watch } from '@vue/composition-api';
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
use([ use([
@ -50,50 +50,55 @@ export default defineComponent({
setup(props) { setup(props) {
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
const botList = ref<string[]>([]); const botList = ref<string[]>([]);
const cumulativeData = computed(() => { const cumulativeData = ref<{ date: number; profit: any }[]>([]);
botList.value = [];
const res: CumProfitData[] = [];
const resD: CumProfitDataPerDate = {};
const closedTrades = props.trades
.slice()
.sort((a, b) => (a.close_timestamp > b.close_timestamp ? 1 : -1));
let profit = 0.0;
for (let i = 0, len = closedTrades.length; i < len; i += 1) { watch(
const trade = closedTrades[i]; () => props.trades,
() => {
botList.value = [];
const res: CumProfitData[] = [];
const resD: CumProfitDataPerDate = {};
const closedTrades = props.trades
.slice()
.sort((a, b) => (a.close_timestamp > b.close_timestamp ? 1 : -1));
let profit = 0.0;
if (trade.close_timestamp && trade[props.profitColumn]) { for (let i = 0, len = closedTrades.length; i < len; i += 1) {
profit += trade[props.profitColumn]; const trade = closedTrades[i];
if (!resD[trade.close_timestamp]) {
// New timestamp if (trade.close_timestamp && trade[props.profitColumn]) {
resD[trade.close_timestamp] = { profit, [trade.botId]: profit }; profit += trade[props.profitColumn];
} else { if (!resD[trade.close_timestamp]) {
// Add to existing profit // New timestamp
resD[trade.close_timestamp].profit += trade[props.profitColumn]; resD[trade.close_timestamp] = { profit, [trade.botId]: profit };
if (resD[trade.close_timestamp][trade.botId]) {
resD[trade.close_timestamp][trade.botId] += trade[props.profitColumn];
} else { } else {
resD[trade.close_timestamp][trade.botId] = profit; // Add to existing profit
resD[trade.close_timestamp].profit += trade[props.profitColumn];
if (resD[trade.close_timestamp][trade.botId]) {
resD[trade.close_timestamp][trade.botId] += trade[props.profitColumn];
} else {
resD[trade.close_timestamp][trade.botId] = profit;
}
}
// console.log(trade.close_date, profit);
res.push({ date: trade.close_timestamp, profit, [trade.botId]: profit });
if (!botList.value.includes(trade.botId)) {
botList.value.push(trade.botId);
} }
} }
// console.log(trade.close_date, profit);
res.push({ date: trade.close_timestamp, profit, [trade.botId]: profit });
if (!botList.value.includes(trade.botId)) {
botList.value.push(trade.botId);
}
} }
} // console.log(resD);
// console.log(resD);
return Object.entries(resD).map(([k, v]) => { cumulativeData.value = Object.entries(resD).map(([k, v]) => {
const obj = { date: parseInt(k, 10), profit: v.profit }; const obj = { date: parseInt(k, 10), profit: v.profit };
// TODO: The below could allow "lines" per bot" // TODO: The below could allow "lines" per bot"
// this.botList.forEach((botId) => { // this.botList.forEach((botId) => {
// obj[botId] = v[botId]; // obj[botId] = v[botId];
// }); // });
return obj; return obj;
}); });
}); },
);
const chartOptions = computed((): EChartsOption => { const chartOptions = computed((): EChartsOption => {
const chartOptionsLoc: EChartsOption = { const chartOptionsLoc: EChartsOption = {

View File

@ -59,11 +59,9 @@
<script lang="ts"> <script lang="ts">
import TradeList from '@/components/ftbot/TradeList.vue'; import TradeList from '@/components/ftbot/TradeList.vue';
import { Component, Vue, Prop } from 'vue-property-decorator';
import { StrategyBacktestResult, Trade } from '@/types'; import { StrategyBacktestResult, Trade } from '@/types';
import ValuePair from '@/components/general/ValuePair.vue'; import { defineComponent, computed } from '@vue/composition-api';
import { import {
timestampms, timestampms,
formatPercent, formatPercent,
@ -71,298 +69,310 @@ import {
humanizeDurationFromSeconds, humanizeDurationFromSeconds,
} from '@/shared/formatters'; } from '@/shared/formatters';
@Component({ export default defineComponent({
name: 'LoginModal',
components: { components: {
TradeList, TradeList,
ValuePair,
}, },
}) props: {
export default class BacktestResultView extends Vue { backtestResult: { required: true, type: Object as () => StrategyBacktestResult },
@Prop({ required: true }) readonly backtestResult!: StrategyBacktestResult; },
setup(props) {
const hasBacktestResult = computed(() => {
return !!props.backtestResult;
});
get hasBacktestResult() { const formatPriceStake = (price) => {
return !!this.backtestResult; return `${formatPrice(price, props.backtestResult.stake_currency_decimals)} ${
} props.backtestResult.stake_currency
}`;
};
const getSortedTrades = (backtestResult: StrategyBacktestResult): Trade[] => {
const sortedTrades = backtestResult.trades
.slice()
.sort((a, b) => a.profit_ratio - b.profit_ratio);
return sortedTrades;
};
getSortedTrades(backtestResult: StrategyBacktestResult): Trade[] { const bestPair = computed((): string => {
const sortedTrades = backtestResult.trades const trades = getSortedTrades(props.backtestResult);
.slice() const value = trades[trades.length - 1];
.sort((a, b) => a.profit_ratio - b.profit_ratio); return `${value.pair} ${formatPercent(value.profit_ratio, 2)}`;
return sortedTrades; });
} const worstPair = computed((): string => {
const trades = getSortedTrades(props.backtestResult);
const value = trades[0];
return `${value.pair} ${formatPercent(value.profit_ratio, 2)}`;
});
const backtestResultStats = computed(() => {
// Transpose Result into readable format
const shortMetrics =
props.backtestResult?.trade_count_short && props.backtestResult?.trade_count_short > 0
? [
{ metric: '___', value: '___' },
{
metric: 'Long / Short',
value: `${props.backtestResult.trade_count_long} / ${props.backtestResult.trade_count_short}`,
},
{
metric: 'Total profit Long',
value: `${formatPercent(
props.backtestResult.profit_total_long || 0,
)} | ${formatPriceStake(props.backtestResult.profit_total_long_abs)}`,
},
{
metric: 'Total profit Short',
value: `${formatPercent(
props.backtestResult.profit_total_short || 0,
)} | ${formatPriceStake(props.backtestResult.profit_total_short_abs)}`,
},
]
: [];
formatPriceStake(price) { return [
return `${formatPrice(price, this.backtestResult.stake_currency_decimals)} ${ {
this.backtestResult.stake_currency metric: 'Total Profit',
}`; value: `${formatPercent(props.backtestResult.profit_total)} | ${formatPriceStake(
} props.backtestResult.profit_total_abs,
)}`,
},
{
metric: 'Total trades / Daily Avg Trades',
value: `${props.backtestResult.total_trades} / ${props.backtestResult.trades_per_day}`,
},
// { metric: 'First trade', value: props.backtestResult.backtest_fi },
// { metric: 'First trade Pair', value: props.backtestResult.backtest_best_day },
{
metric: 'Best day',
value: `${formatPercent(props.backtestResult.backtest_best_day, 2)} | ${formatPriceStake(
props.backtestResult.backtest_best_day_abs,
)}`,
},
{
metric: 'Worst day',
value: `${formatPercent(props.backtestResult.backtest_worst_day, 2)} | ${formatPriceStake(
props.backtestResult.backtest_worst_day_abs,
)}`,
},
get bestPair(): string { {
const trades = this.getSortedTrades(this.backtestResult); metric: 'Win/Draw/Loss',
const value = trades[trades.length - 1]; value: `${
return `${value.pair} ${formatPercent(value.profit_ratio, 2)}`; props.backtestResult.results_per_pair[props.backtestResult.results_per_pair.length - 1]
} .wins
} / ${
props.backtestResult.results_per_pair[props.backtestResult.results_per_pair.length - 1]
.draws
} / ${
props.backtestResult.results_per_pair[props.backtestResult.results_per_pair.length - 1]
.losses
}`,
},
{
metric: 'Days win/draw/loss',
value: `${props.backtestResult.winning_days} / ${props.backtestResult.draw_days} / ${props.backtestResult.losing_days}`,
},
get worstPair(): string { {
const trades = this.getSortedTrades(this.backtestResult); metric: 'Avg. Duration winners',
const value = trades[0]; value: humanizeDurationFromSeconds(props.backtestResult.winner_holding_avg),
return `${value.pair} ${formatPercent(value.profit_ratio, 2)}`; },
} {
metric: 'Avg. Duration Losers',
value: humanizeDurationFromSeconds(props.backtestResult.loser_holding_avg),
},
{ metric: 'Rejected entry signals', value: props.backtestResult.rejected_signals },
{
metric: 'Entry/Exit timeouts',
value: `${props.backtestResult.timedout_entry_orders} / ${props.backtestResult.timedout_exit_orders}`,
},
get backtestResultStats() { ...shortMetrics,
// Transpose Result into readable format
const shortMetrics =
this.backtestResult?.trade_count_short && this.backtestResult?.trade_count_short > 0
? [
{ metric: '___', value: '___' },
{
metric: 'Long / Short',
value: `${this.backtestResult.trade_count_long} / ${this.backtestResult.trade_count_short}`,
},
{
metric: 'Total profit Long',
value: `${formatPercent(
this.backtestResult.profit_total_long || 0,
)} | ${this.formatPriceStake(this.backtestResult.profit_total_long_abs)}`,
},
{
metric: 'Total profit Short',
value: `${formatPercent(
this.backtestResult.profit_total_short || 0,
)} | ${this.formatPriceStake(this.backtestResult.profit_total_short_abs)}`,
},
]
: [];
return [ { metric: '___', value: '___' },
{ { metric: 'Min balance', value: formatPriceStake(props.backtestResult.csum_min) },
metric: 'Total Profit', { metric: 'Max balance', value: formatPriceStake(props.backtestResult.csum_max) },
value: `${formatPercent(this.backtestResult.profit_total)} | ${this.formatPriceStake( { metric: 'Market change', value: formatPercent(props.backtestResult.market_change) },
this.backtestResult.profit_total_abs, { metric: '___', value: '___' },
)}`, {
}, metric: 'Max Drawdown (Account)',
{ value: formatPercent(props.backtestResult.max_drawdown_account),
metric: 'Total trades / Daily Avg Trades', },
value: `${this.backtestResult.total_trades} / ${this.backtestResult.trades_per_day}`, {
}, metric: 'Max Drawdown ABS',
// { metric: 'First trade', value: this.backtestResult.backtest_fi }, value: formatPriceStake(props.backtestResult.max_drawdown_abs),
// { metric: 'First trade Pair', value: this.backtestResult.backtest_best_day }, },
{ {
metric: 'Best day', metric: 'Drawdown high | low',
value: `${formatPercent( value: `${formatPriceStake(props.backtestResult.max_drawdown_high)} | ${formatPriceStake(
this.backtestResult.backtest_best_day, props.backtestResult.max_drawdown_low,
2, )}`,
)} | ${this.formatPriceStake(this.backtestResult.backtest_best_day_abs)}`, },
}, { metric: 'Drawdown start', value: timestampms(props.backtestResult.drawdown_start_ts) },
{ { metric: 'Drawdown end', value: timestampms(props.backtestResult.drawdown_end_ts) },
metric: 'Worst day', { metric: '___', value: '___' },
value: `${formatPercent(
this.backtestResult.backtest_worst_day,
2,
)} | ${this.formatPriceStake(this.backtestResult.backtest_worst_day_abs)}`,
},
{ {
metric: 'Win/Draw/Loss', metric: 'Best Pair',
value: `${ value: `${props.backtestResult.best_pair.key} ${formatPercent(
this.backtestResult.results_per_pair[this.backtestResult.results_per_pair.length - 1].wins props.backtestResult.best_pair.profit_sum,
} / ${ )}`,
this.backtestResult.results_per_pair[this.backtestResult.results_per_pair.length - 1] },
.draws {
} / ${ metric: 'Worst Pair',
this.backtestResult.results_per_pair[this.backtestResult.results_per_pair.length - 1] value: `${props.backtestResult.worst_pair.key} ${formatPercent(
.losses props.backtestResult.worst_pair.profit_sum,
}`, )}`,
}, },
{ { metric: 'Best single Trade', value: bestPair },
metric: 'Days win/draw/loss', { metric: 'Worst single Trade', value: worstPair },
value: `${this.backtestResult.winning_days} / ${this.backtestResult.draw_days} / ${this.backtestResult.losing_days}`, ];
}, });
{ const backtestResultSettings = computed(() => {
metric: 'Avg. Duration winners', // Transpose Result into readable format
value: humanizeDurationFromSeconds(this.backtestResult.winner_holding_avg), return [
}, { setting: 'Backtesting from', value: timestampms(props.backtestResult.backtest_start_ts) },
{ { setting: 'Backtesting to', value: timestampms(props.backtestResult.backtest_end_ts) },
metric: 'Avg. Duration Losers', {
value: humanizeDurationFromSeconds(this.backtestResult.loser_holding_avg), setting: 'BT execution time',
}, value: humanizeDurationFromSeconds(
{ metric: 'Rejected entry signals', value: this.backtestResult.rejected_signals }, props.backtestResult.backtest_run_end_ts - props.backtestResult.backtest_run_start_ts,
{ ),
metric: 'Entry/Exit timeouts', },
value: `${this.backtestResult.timedout_entry_orders} / ${this.backtestResult.timedout_exit_orders}`, { setting: 'Max open trades', value: props.backtestResult.max_open_trades },
}, { setting: 'Timeframe', value: props.backtestResult.timeframe },
{ setting: 'Timerange', value: props.backtestResult.timerange },
{ setting: 'Stoploss', value: formatPercent(props.backtestResult.stoploss, 2) },
{ setting: 'Trailing Stoploss', value: props.backtestResult.trailing_stop },
{
setting: 'Trail only when offset is reached',
value: props.backtestResult.trailing_only_offset_is_reached,
},
{ setting: 'Trailing Stop positive', value: props.backtestResult.trailing_stop_positive },
{
setting: 'Trailing stop positive offset',
value: props.backtestResult.trailing_stop_positive_offset,
},
{ setting: 'Custom Stoploss', value: props.backtestResult.use_custom_stoploss },
{ setting: 'ROI', value: props.backtestResult.minimal_roi },
{
setting: 'Use Exit Signal',
value:
props.backtestResult.use_exit_signal !== undefined
? props.backtestResult.use_exit_signal
: props.backtestResult.use_sell_signal,
},
{
setting: 'Exit profit only',
value:
props.backtestResult.exit_profit_only !== undefined
? props.backtestResult.exit_profit_only
: props.backtestResult.sell_profit_only,
},
{
setting: 'Exit profit offset',
value:
props.backtestResult.exit_profit_offset !== undefined
? props.backtestResult.exit_profit_offset
: props.backtestResult.sell_profit_offset,
},
{ setting: 'Enable protections', value: props.backtestResult.enable_protections },
{
setting: 'Starting balance',
value: formatPriceStake(props.backtestResult.starting_balance),
},
{
setting: 'Final balance',
value: formatPriceStake(props.backtestResult.final_balance),
},
{
setting: 'Avg. stake amount',
value: formatPriceStake(props.backtestResult.avg_stake_amount),
},
{
setting: 'Total trade volume',
value: formatPriceStake(props.backtestResult.total_volume),
},
];
});
const perPairFields = computed(() => {
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) },
{
key: 'profit_total_abs',
label: `Tot Profit ${props.backtestResult.stake_currency}`,
formatter: (value) => formatPrice(value, props.backtestResult.stake_currency_decimals),
},
{
key: 'profit_total',
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' },
];
});
...shortMetrics, const perExitReason = computed(() => {
return [
{ key: 'exit_reason', label: 'Exit 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 ${props.backtestResult.stake_currency}`,
{ metric: '___', value: '___' }, formatter: (value) => formatPrice(value, props.backtestResult.stake_currency_decimals),
{ metric: 'Min balance', value: this.formatPriceStake(this.backtestResult.csum_min) }, },
{ metric: 'Max balance', value: this.formatPriceStake(this.backtestResult.csum_max) }, {
{ metric: 'Market change', value: formatPercent(this.backtestResult.market_change) }, key: 'profit_total',
{ metric: '___', value: '___' }, label: 'Tot Profit %',
{ formatter: (value) => formatPercent(value, 2),
metric: 'Max Drawdown (Account)', },
value: formatPercent(this.backtestResult.max_drawdown_account), { key: 'wins', label: 'Wins' },
}, { key: 'draws', label: 'Draws' },
{ { key: 'losses', label: 'Losses' },
metric: 'Max Drawdown ABS', ];
value: this.formatPriceStake(this.backtestResult.max_drawdown_abs), });
}, const backtestResultFields: Array<Record<string, string>> = [
{ { key: 'metric', label: 'Metric' },
metric: 'Drawdown high | low', { key: 'value', label: 'Value' },
value: `${this.formatPriceStake(
this.backtestResult.max_drawdown_high,
)} | ${this.formatPriceStake(this.backtestResult.max_drawdown_low)}`,
},
{ metric: 'Drawdown start', value: timestampms(this.backtestResult.drawdown_start_ts) },
{ metric: 'Drawdown end', value: timestampms(this.backtestResult.drawdown_end_ts) },
{ metric: '___', value: '___' },
{
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,
)}`,
},
{ metric: 'Best single Trade', value: this.bestPair },
{ metric: 'Worst single Trade', value: this.worstPair },
]; ];
}
timestampms = timestampms; const backtestsettingFields: Array<Record<string, string>> = [
{ key: 'setting', label: 'Setting' },
formatPercent = formatPercent; { key: 'value', label: 'Value' },
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: 'BT execution time',
value: humanizeDurationFromSeconds(
this.backtestResult.backtest_run_end_ts - this.backtestResult.backtest_run_start_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 Exit Signal',
value:
this.backtestResult.use_exit_signal !== undefined
? this.backtestResult.use_exit_signal
: this.backtestResult.use_sell_signal,
},
{
setting: 'Exit profit only',
value:
this.backtestResult.exit_profit_only !== undefined
? this.backtestResult.exit_profit_only
: this.backtestResult.sell_profit_only,
},
{
setting: 'Exit profit offset',
value:
this.backtestResult.exit_profit_offset !== undefined
? this.backtestResult.exit_profit_offset
: this.backtestResult.sell_profit_offset,
},
{ setting: 'Enable protections', value: this.backtestResult.enable_protections },
{
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),
},
]; ];
}
get perPairFields() { return {
return [ hasBacktestResult,
{ key: 'key', label: 'Pair' }, formatPriceStake,
{ key: 'trades', label: 'Buys' }, bestPair,
{ key: 'profit_mean', label: 'Avg Profit %', formatter: (value) => formatPercent(value, 2) }, worstPair,
{ key: 'profit_sum', label: 'Cum Profit %', formatter: (value) => formatPercent(value, 2) }, backtestResultStats,
{ backtestResultSettings,
key: 'profit_total_abs', perPairFields,
label: `Tot Profit ${this.backtestResult.stake_currency}`, perExitReason,
formatter: (value) => formatPrice(value, this.backtestResult.stake_currency_decimals), backtestResultFields,
}, backtestsettingFields,
{ };
key: 'profit_total', },
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 perExitReason() {
return [
{ key: 'exit_reason', label: 'Exit 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}`,
formatter: (value) => formatPrice(value, this.backtestResult.stake_currency_decimals),
},
{
key: 'profit_total',
label: 'Tot Profit %',
formatter: (value) => formatPercent(value, 2),
},
{ key: 'wins', label: 'Wins' },
{ key: 'draws', label: 'Draws' },
{ key: 'losses', label: 'Losses' },
];
}
backtestResultFields: Array<Record<string, string>> = [
{ key: 'metric', label: 'Metric' },
{ key: 'value', label: 'Value' },
];
backtestsettingFields: Array<Record<string, string>> = [
{ key: 'setting', label: 'Setting' },
{ key: 'value', label: 'Value' },
];
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -37,61 +37,64 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Emit, Prop, Watch } from 'vue-property-decorator';
import { dateFromString, dateStringToTimeRange, timestampToDateString } from '@/shared/formatters'; import { dateFromString, dateStringToTimeRange, timestampToDateString } from '@/shared/formatters';
import { defineComponent, ref, computed, onMounted, watch } from '@vue/composition-api';
const now = new Date(); const now = new Date();
@Component({})
export default class TimeRangeSelect extends Vue {
dateFrom = '';
dateTo = ''; export default defineComponent({
name: 'TimeRangeSelect',
props: {
value: { required: true, type: String },
},
setup(props, { emit }) {
const dateFrom = ref<string>('');
const dateTo = ref<string>('');
@Prop() value!: string; const timeRange = computed(() => {
if (dateFrom.value !== '' || dateTo.value !== '') {
return `${dateStringToTimeRange(dateFrom.value)}-${dateStringToTimeRange(dateTo.value)}`;
}
return '';
});
@Emit('input') const updated = () => {
emitTimeRange() { emit('input', timeRange.value);
return this.timeRange; };
}
@Watch('value') const updateInput = () => {
valueChanged(val) { const tr = props.value.split('-');
console.log('TimeRange', val); if (tr[0]) {
if (val !== this.value) { dateFrom.value = timestampToDateString(dateFromString(tr[0], 'yyyyMMdd'));
this.updateInput(); }
} if (tr.length > 1 && tr[1]) {
} dateTo.value = timestampToDateString(dateFromString(tr[1], 'yyyyMMdd'));
}
updated();
};
updateInput() { watch(
const tr = this.value.split('-'); () => timeRange.value,
if (tr[0]) { () => updated(),
this.dateFrom = timestampToDateString(dateFromString(tr[0], 'yyyyMMdd')); );
}
if (tr.length > 1 && tr[1]) {
this.dateTo = timestampToDateString(dateFromString(tr[1], 'yyyyMMdd'));
}
}
created() { onMounted(() => {
if (!this.value) { if (!props.value) {
this.dateFrom = timestampToDateString(new Date(now.getFullYear(), now.getMonth() - 1, 1)); dateFrom.value = timestampToDateString(new Date(now.getFullYear(), now.getMonth() - 1, 1));
} else { } else {
this.updateInput(); updateInput();
} }
this.emitTimeRange(); emit('input', timeRange.value);
} });
updated() { return {
this.emitTimeRange(); dateFrom,
} dateTo,
timeRange,
get timeRange() { updated,
if (this.dateFrom !== '' || this.dateTo !== '') { };
return `${dateStringToTimeRange(this.dateFrom)}-${dateStringToTimeRange(this.dateTo)}`; },
} });
return '';
}
}
</script> </script>
<style scoped></style> <style scoped></style>