mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-26 21:15:15 +00:00
Final components to script setup
This commit is contained in:
parent
85820c8684
commit
ff1b217ca9
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<v-chart v-if="trades" :option="chartOptions" autoresize :theme="settingsStore.chartTheme" />
|
<e-charts v-if="trades" :option="chartOptions" autoresize :theme="settingsStore.chartTheme" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
import { EChartsOption } from 'echarts';
|
import { EChartsOption } from 'echarts';
|
||||||
|
|
||||||
|
@ -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, computed, ComputedRef } from 'vue';
|
import { computed, ComputedRef } from 'vue';
|
||||||
import { useSettingsStore } from '@/stores/settings';
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import { dataZoomPartial } from '@/shared/charts/chartZoom';
|
import { dataZoomPartial } from '@/shared/charts/chartZoom';
|
||||||
|
|
||||||
|
@ -38,157 +38,147 @@ use([
|
||||||
// Define Column labels here to avoid typos
|
// Define Column labels here to avoid typos
|
||||||
const CHART_PROFIT = 'Profit';
|
const CHART_PROFIT = 'Profit';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'CumProfitChart',
|
trades: { required: true, type: Array as () => ClosedTrade[] },
|
||||||
components: {
|
showTitle: { default: true, type: Boolean },
|
||||||
'v-chart': ECharts,
|
profitColumn: { default: 'profit_abs', type: String },
|
||||||
},
|
});
|
||||||
props: {
|
const settingsStore = useSettingsStore();
|
||||||
trades: { required: true, type: Array as () => ClosedTrade[] },
|
// const botList = ref<string[]>([]);
|
||||||
showTitle: { default: true, type: Boolean },
|
// const cumulativeData = ref<{ date: number; profit: any }[]>([]);
|
||||||
profitColumn: { default: 'profit_abs', type: String },
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
// const botList = ref<string[]>([]);
|
|
||||||
// const cumulativeData = ref<{ date: number; profit: any }[]>([]);
|
|
||||||
|
|
||||||
const cumulativeData: ComputedRef<{ date: number; profit: number }[]> = computed(() => {
|
const cumulativeData: ComputedRef<{ date: number; profit: number }[]> = computed(() => {
|
||||||
const res: CumProfitData[] = [];
|
const res: CumProfitData[] = [];
|
||||||
const resD: CumProfitDataPerDate = {};
|
const resD: CumProfitDataPerDate = {};
|
||||||
const closedTrades = props.trades
|
const closedTrades = props.trades
|
||||||
.slice()
|
.slice()
|
||||||
.sort((a, b) => (a.close_timestamp > b.close_timestamp ? 1 : -1));
|
.sort((a, b) => (a.close_timestamp > b.close_timestamp ? 1 : -1));
|
||||||
let profit = 0.0;
|
let profit = 0.0;
|
||||||
|
|
||||||
for (let i = 0, len = closedTrades.length; i < len; i += 1) {
|
for (let i = 0, len = closedTrades.length; i < len; i += 1) {
|
||||||
const trade = closedTrades[i];
|
const trade = closedTrades[i];
|
||||||
|
|
||||||
if (trade.close_timestamp && trade[props.profitColumn]) {
|
if (trade.close_timestamp && trade[props.profitColumn]) {
|
||||||
profit += trade[props.profitColumn];
|
profit += trade[props.profitColumn];
|
||||||
if (!resD[trade.close_timestamp]) {
|
if (!resD[trade.close_timestamp]) {
|
||||||
// New timestamp
|
// New timestamp
|
||||||
resD[trade.close_timestamp] = { profit, [trade.botId]: profit };
|
resD[trade.close_timestamp] = { profit, [trade.botId]: profit };
|
||||||
} else {
|
} else {
|
||||||
// Add to existing profit
|
// Add to existing profit
|
||||||
resD[trade.close_timestamp].profit += trade[props.profitColumn];
|
resD[trade.close_timestamp].profit += trade[props.profitColumn];
|
||||||
if (resD[trade.close_timestamp][trade.botId]) {
|
if (resD[trade.close_timestamp][trade.botId]) {
|
||||||
resD[trade.close_timestamp][trade.botId] += trade[props.profitColumn];
|
resD[trade.close_timestamp][trade.botId] += trade[props.profitColumn];
|
||||||
} else {
|
} else {
|
||||||
resD[trade.close_timestamp][trade.botId] = profit;
|
resD[trade.close_timestamp][trade.botId] = profit;
|
||||||
}
|
|
||||||
}
|
|
||||||
res.push({ date: trade.close_timestamp, profit, [trade.botId]: profit });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log(resD);
|
res.push({ date: trade.close_timestamp, profit, [trade.botId]: profit });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(resD);
|
||||||
|
|
||||||
return Object.entries(resD).map(([k, v]) => {
|
return 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 = {
|
||||||
title: {
|
title: {
|
||||||
text: 'Cumulative Profit',
|
text: 'Cumulative Profit',
|
||||||
show: props.showTitle,
|
show: props.showTitle,
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0)',
|
||||||
|
dataset: {
|
||||||
|
dimensions: ['date', 'profit'],
|
||||||
|
source: cumulativeData.value,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985',
|
||||||
},
|
},
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0)',
|
},
|
||||||
dataset: {
|
},
|
||||||
dimensions: ['date', 'profit'],
|
legend: {
|
||||||
source: cumulativeData.value,
|
data: [CHART_PROFIT],
|
||||||
|
right: '5%',
|
||||||
|
},
|
||||||
|
useUTC: false,
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: CHART_PROFIT,
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
},
|
},
|
||||||
tooltip: {
|
nameRotate: 90,
|
||||||
trigger: 'axis',
|
nameLocation: 'middle',
|
||||||
axisPointer: {
|
nameGap: 40,
|
||||||
type: 'line',
|
},
|
||||||
label: {
|
],
|
||||||
backgroundColor: '#6a7985',
|
grid: {
|
||||||
},
|
bottom: 80,
|
||||||
},
|
},
|
||||||
},
|
dataZoom: [
|
||||||
legend: {
|
{
|
||||||
data: [CHART_PROFIT],
|
type: 'inside',
|
||||||
right: '5%',
|
// xAxisIndex: [0],
|
||||||
},
|
start: 0,
|
||||||
useUTC: false,
|
|
||||||
xAxis: {
|
|
||||||
type: 'time',
|
|
||||||
},
|
|
||||||
yAxis: [
|
|
||||||
{
|
|
||||||
type: 'value',
|
|
||||||
name: CHART_PROFIT,
|
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
nameRotate: 90,
|
|
||||||
nameLocation: 'middle',
|
|
||||||
nameGap: 40,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
grid: {
|
|
||||||
bottom: 80,
|
|
||||||
},
|
|
||||||
dataZoom: [
|
|
||||||
{
|
|
||||||
type: 'inside',
|
|
||||||
// xAxisIndex: [0],
|
|
||||||
start: 0,
|
|
||||||
|
|
||||||
end: 100,
|
end: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// xAxisIndex: [0],
|
// xAxisIndex: [0],
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 100,
|
end: 100,
|
||||||
...dataZoomPartial,
|
...dataZoomPartial,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
type: 'line',
|
type: 'line',
|
||||||
name: CHART_PROFIT,
|
name: CHART_PROFIT,
|
||||||
animation: true,
|
animation: true,
|
||||||
step: 'end',
|
step: 'end',
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: settingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
color: settingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: settingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
color: settingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
||||||
},
|
},
|
||||||
// symbol: 'none',
|
// symbol: 'none',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
// TODO: maybe have profit lines per bot?
|
// TODO: maybe have profit lines per bot?
|
||||||
// this.botList.forEach((botId: string) => {
|
// this.botList.forEach((botId: string) => {
|
||||||
// console.log('bot', botId);
|
// console.log('bot', botId);
|
||||||
// chartOptionsLoc.series.push({
|
// chartOptionsLoc.series.push({
|
||||||
// type: 'line',
|
// type: 'line',
|
||||||
// name: botId,
|
// name: botId,
|
||||||
// animation: true,
|
// animation: true,
|
||||||
// step: 'end',
|
// step: 'end',
|
||||||
// lineStyle: {
|
// lineStyle: {
|
||||||
// color: settingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
// color: settingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
||||||
// },
|
// },
|
||||||
// itemStylesettingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
// itemStylesettingsStore.chartTheme === 'dark' ? '#c2c2c2' : 'black',
|
||||||
// },
|
// },
|
||||||
// // symbol: 'none',
|
// // symbol: 'none',
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
return chartOptionsLoc;
|
return chartOptionsLoc;
|
||||||
});
|
|
||||||
|
|
||||||
return { settingsStore, cumulativeData, chartOptions };
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<v-chart
|
<e-charts
|
||||||
v-if="dailyStats.data"
|
v-if="dailyStats.data"
|
||||||
:option="dailyChartOptions"
|
:option="dailyChartOptions"
|
||||||
:theme="settingsStore.chartTheme"
|
:theme="settingsStore.chartTheme"
|
||||||
|
@ -7,8 +7,8 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent, computed, ComputedRef } from 'vue';
|
import { computed, ComputedRef } from 'vue';
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
// import { EChartsOption } from 'echarts';
|
// import { EChartsOption } from 'echarts';
|
||||||
|
|
||||||
|
@ -44,125 +44,113 @@ use([
|
||||||
const CHART_ABS_PROFIT = 'Absolute profit';
|
const CHART_ABS_PROFIT = 'Absolute profit';
|
||||||
const CHART_TRADE_COUNT = 'Trade Count';
|
const CHART_TRADE_COUNT = 'Trade Count';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
components: {
|
dailyStats: {
|
||||||
'v-chart': ECharts,
|
type: Object as () => DailyReturnValue,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
props: {
|
showTitle: {
|
||||||
dailyStats: {
|
type: Boolean,
|
||||||
type: Object as () => DailyReturnValue,
|
default: true,
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
showTitle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setup(props) {
|
const settingsStore = useSettingsStore();
|
||||||
const settingsStore = useSettingsStore();
|
const absoluteMin = computed(() =>
|
||||||
const absoluteMin = computed(() =>
|
props.dailyStats.data.reduce(
|
||||||
props.dailyStats.data.reduce(
|
(min, p) => (p.abs_profit < min ? p.abs_profit : min),
|
||||||
(min, p) => (p.abs_profit < min ? p.abs_profit : min),
|
props.dailyStats.data[0]?.abs_profit,
|
||||||
props.dailyStats.data[0]?.abs_profit,
|
),
|
||||||
),
|
);
|
||||||
);
|
const absoluteMax = computed(() =>
|
||||||
const absoluteMax = computed(() =>
|
props.dailyStats.data.reduce(
|
||||||
props.dailyStats.data.reduce(
|
(max, p) => (p.abs_profit > max ? p.abs_profit : max),
|
||||||
(max, p) => (p.abs_profit > max ? p.abs_profit : max),
|
props.dailyStats.data[0]?.abs_profit,
|
||||||
props.dailyStats.data[0]?.abs_profit,
|
),
|
||||||
),
|
);
|
||||||
);
|
const dailyChartOptions: ComputedRef<EChartsOption> = computed(() => {
|
||||||
const dailyChartOptions: ComputedRef<EChartsOption> = computed(() => {
|
return {
|
||||||
return {
|
title: {
|
||||||
title: {
|
text: 'Daily profit',
|
||||||
text: 'Daily profit',
|
show: props.showTitle,
|
||||||
show: props.showTitle,
|
},
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0)',
|
||||||
|
dataset: {
|
||||||
|
dimensions: ['date', 'abs_profit', 'trade_count'],
|
||||||
|
source: props.dailyStats.data,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985',
|
||||||
},
|
},
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0)',
|
},
|
||||||
dataset: {
|
},
|
||||||
dimensions: ['date', 'abs_profit', 'trade_count'],
|
legend: {
|
||||||
source: props.dailyStats.data,
|
data: [CHART_ABS_PROFIT, CHART_TRADE_COUNT],
|
||||||
},
|
right: '5%',
|
||||||
tooltip: {
|
},
|
||||||
trigger: 'axis',
|
xAxis: [
|
||||||
axisPointer: {
|
{
|
||||||
type: 'line',
|
type: 'category',
|
||||||
label: {
|
},
|
||||||
backgroundColor: '#6a7985',
|
],
|
||||||
},
|
visualMap: [
|
||||||
},
|
{
|
||||||
},
|
dimension: 1,
|
||||||
legend: {
|
seriesIndex: 0,
|
||||||
data: [CHART_ABS_PROFIT, CHART_TRADE_COUNT],
|
show: false,
|
||||||
right: '5%',
|
pieces: [
|
||||||
},
|
|
||||||
xAxis: [
|
|
||||||
{
|
{
|
||||||
type: 'category',
|
max: 0.0,
|
||||||
|
min: absoluteMin.value,
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 0.0,
|
||||||
|
max: absoluteMax.value,
|
||||||
|
color: 'green',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
visualMap: [
|
},
|
||||||
{
|
],
|
||||||
dimension: 1,
|
yAxis: [
|
||||||
seriesIndex: 0,
|
{
|
||||||
show: false,
|
type: 'value',
|
||||||
pieces: [
|
name: CHART_ABS_PROFIT,
|
||||||
{
|
splitLine: {
|
||||||
max: 0.0,
|
show: false,
|
||||||
min: absoluteMin.value,
|
},
|
||||||
color: 'red',
|
nameRotate: 90,
|
||||||
},
|
nameLocation: 'middle',
|
||||||
{
|
nameGap: 40,
|
||||||
min: 0.0,
|
},
|
||||||
max: absoluteMax.value,
|
{
|
||||||
color: 'green',
|
type: 'value',
|
||||||
},
|
name: CHART_TRADE_COUNT,
|
||||||
],
|
nameRotate: 90,
|
||||||
},
|
nameLocation: 'middle',
|
||||||
],
|
nameGap: 30,
|
||||||
yAxis: [
|
},
|
||||||
{
|
],
|
||||||
type: 'value',
|
series: [
|
||||||
name: CHART_ABS_PROFIT,
|
{
|
||||||
splitLine: {
|
type: 'line',
|
||||||
show: false,
|
name: CHART_ABS_PROFIT,
|
||||||
},
|
// Color is induced by visualMap
|
||||||
nameRotate: 90,
|
},
|
||||||
nameLocation: 'middle',
|
{
|
||||||
nameGap: 40,
|
type: 'bar',
|
||||||
},
|
name: CHART_TRADE_COUNT,
|
||||||
{
|
itemStyle: {
|
||||||
type: 'value',
|
color: 'rgba(150,150,150,0.3)',
|
||||||
name: CHART_TRADE_COUNT,
|
},
|
||||||
nameRotate: 90,
|
yAxisIndex: 1,
|
||||||
nameLocation: 'middle',
|
},
|
||||||
nameGap: 30,
|
],
|
||||||
},
|
};
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
name: CHART_ABS_PROFIT,
|
|
||||||
// Color is induced by visualMap
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'bar',
|
|
||||||
name: CHART_TRADE_COUNT,
|
|
||||||
itemStyle: {
|
|
||||||
color: 'rgba(150,150,150,0.3)',
|
|
||||||
},
|
|
||||||
yAxisIndex: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
dailyChartOptions,
|
|
||||||
settingsStore,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<v-chart
|
<e-charts
|
||||||
v-if="trades.length > 0"
|
v-if="trades.length > 0"
|
||||||
:option="hourlyChartOptions"
|
:option="hourlyChartOptions"
|
||||||
autoresize
|
autoresize
|
||||||
|
@ -7,10 +7,10 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
import { useSettingsStore } from '@/stores/settings';
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import { defineComponent, computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { Trade } from '@/types';
|
import { Trade } from '@/types';
|
||||||
import { timestampHour } from '@/shared/formatters';
|
import { timestampHour } from '@/shared/formatters';
|
||||||
|
@ -45,121 +45,112 @@ use([
|
||||||
const CHART_PROFIT = 'Profit %';
|
const CHART_PROFIT = 'Profit %';
|
||||||
const CHART_TRADE_COUNT = 'Trade Count';
|
const CHART_TRADE_COUNT = 'Trade Count';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'HourlyChart',
|
trades: { required: true, type: Array as () => Trade[] },
|
||||||
components: {
|
showTitle: { default: true, type: Boolean },
|
||||||
'v-chart': ECharts,
|
});
|
||||||
},
|
const settingsStore = useSettingsStore();
|
||||||
props: {
|
|
||||||
trades: { required: true, type: Array as () => Trade[] },
|
|
||||||
showTitle: { default: true, type: Boolean },
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
|
|
||||||
const hourlyData = computed(() => {
|
const hourlyData = computed(() => {
|
||||||
const res = new Array(24);
|
const res = new Array(24);
|
||||||
for (let i = 0; i < 24; i += 1) {
|
for (let i = 0; i < 24; i += 1) {
|
||||||
res[i] = { hour: i, hourDesc: `${i}h`, profit: 0.0, count: 0.0 };
|
res[i] = { hour: i, hourDesc: `${i}h`, profit: 0.0, count: 0.0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0, len = props.trades.length; i < len; i += 1) {
|
for (let i = 0, len = props.trades.length; i < len; i += 1) {
|
||||||
const trade = props.trades[i];
|
const trade = props.trades[i];
|
||||||
if (trade.close_timestamp) {
|
if (trade.close_timestamp) {
|
||||||
const hour = timestampHour(trade.close_timestamp);
|
const hour = timestampHour(trade.close_timestamp);
|
||||||
|
|
||||||
res[hour].profit += trade.profit_ratio;
|
res[hour].profit += trade.profit_ratio;
|
||||||
res[hour].count += 1;
|
res[hour].count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
const hourlyChartOptions = computed((): EChartsOption => {
|
const hourlyChartOptions = computed((): EChartsOption => {
|
||||||
return {
|
return {
|
||||||
title: {
|
title: {
|
||||||
text: 'Hourly Profit',
|
text: 'Hourly Profit',
|
||||||
show: props.showTitle,
|
show: props.showTitle,
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0)',
|
||||||
|
dataset: {
|
||||||
|
dimensions: ['hourDesc', 'profit', 'count'],
|
||||||
|
source: hourlyData.value,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985',
|
||||||
},
|
},
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0)',
|
},
|
||||||
dataset: {
|
},
|
||||||
dimensions: ['hourDesc', 'profit', 'count'],
|
legend: {
|
||||||
source: hourlyData.value,
|
data: [CHART_PROFIT, CHART_TRADE_COUNT],
|
||||||
|
right: '5%',
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: CHART_PROFIT,
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
},
|
},
|
||||||
tooltip: {
|
nameRotate: 90,
|
||||||
trigger: 'axis',
|
nameLocation: 'middle',
|
||||||
axisPointer: {
|
nameGap: 30,
|
||||||
type: 'line',
|
},
|
||||||
label: {
|
{
|
||||||
backgroundColor: '#6a7985',
|
type: 'value',
|
||||||
},
|
name: CHART_TRADE_COUNT,
|
||||||
},
|
nameRotate: 90,
|
||||||
},
|
nameLocation: 'middle',
|
||||||
legend: {
|
nameGap: 30,
|
||||||
data: [CHART_PROFIT, CHART_TRADE_COUNT],
|
},
|
||||||
right: '5%',
|
],
|
||||||
},
|
visualMap: [
|
||||||
xAxis: {
|
{
|
||||||
type: 'category',
|
dimension: 1,
|
||||||
},
|
seriesIndex: 0,
|
||||||
yAxis: [
|
show: false,
|
||||||
|
pieces: [
|
||||||
{
|
{
|
||||||
type: 'value',
|
max: 0.0,
|
||||||
name: CHART_PROFIT,
|
min: -2,
|
||||||
splitLine: {
|
color: 'red',
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
nameRotate: 90,
|
|
||||||
nameLocation: 'middle',
|
|
||||||
nameGap: 30,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'value',
|
min: 0.0,
|
||||||
name: CHART_TRADE_COUNT,
|
max: 2,
|
||||||
nameRotate: 90,
|
color: 'green',
|
||||||
nameLocation: 'middle',
|
|
||||||
nameGap: 30,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
visualMap: [
|
},
|
||||||
{
|
],
|
||||||
dimension: 1,
|
series: [
|
||||||
seriesIndex: 0,
|
{
|
||||||
show: false,
|
type: 'line',
|
||||||
pieces: [
|
name: CHART_PROFIT,
|
||||||
{
|
animation: false,
|
||||||
max: 0.0,
|
// symbol: 'none',
|
||||||
min: -2,
|
},
|
||||||
color: 'red',
|
{
|
||||||
},
|
type: 'bar',
|
||||||
{
|
name: CHART_TRADE_COUNT,
|
||||||
min: 0.0,
|
animation: false,
|
||||||
max: 2,
|
itemStyle: {
|
||||||
color: 'green',
|
color: 'rgba(150,150,150,0.3)',
|
||||||
},
|
},
|
||||||
],
|
yAxisIndex: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
series: [
|
};
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
name: CHART_PROFIT,
|
|
||||||
animation: false,
|
|
||||||
// symbol: 'none',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'bar',
|
|
||||||
name: CHART_TRADE_COUNT,
|
|
||||||
animation: false,
|
|
||||||
itemStyle: {
|
|
||||||
color: 'rgba(150,150,150,0.3)',
|
|
||||||
},
|
|
||||||
yAxisIndex: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return { settingsStore, hourlyChartOptions };
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="d-flex flex-column h-100 position-relative">
|
<div class="d-flex flex-column h-100 position-relative">
|
||||||
<div class="flex-grow-1 order-2">
|
<div class="flex-grow-1 order-2">
|
||||||
<v-chart v-if="trades" :option="chartOptions" autoresize :theme="settingsStore.chartTheme" />
|
<e-charts v-if="trades" :option="chartOptions" autoresize :theme="settingsStore.chartTheme" />
|
||||||
</div>
|
</div>
|
||||||
<b-form-group
|
<b-form-group
|
||||||
class="w-25 order-1"
|
class="w-25 order-1"
|
||||||
|
@ -22,8 +22,8 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent, computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
import { EChartsOption } from 'echarts';
|
import { EChartsOption } from 'echarts';
|
||||||
|
|
||||||
|
@ -57,92 +57,82 @@ use([
|
||||||
// Define Column labels here to avoid typos
|
// Define Column labels here to avoid typos
|
||||||
const CHART_PROFIT = 'Trade count';
|
const CHART_PROFIT = 'Trade count';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'ProfitDistributionChart',
|
trades: { required: true, type: Array as () => ClosedTrade[] },
|
||||||
components: {
|
showTitle: { default: true, type: Boolean },
|
||||||
'v-chart': ECharts,
|
});
|
||||||
},
|
const settingsStore = useSettingsStore();
|
||||||
props: {
|
// registerTransform(ecStat.transform.histogram);
|
||||||
trades: { required: true, type: Array as () => ClosedTrade[] },
|
// console.log(profits);
|
||||||
showTitle: { default: true, type: Boolean },
|
// const data = [[]];
|
||||||
},
|
const binOptions = [10, 15, 20, 25, 50];
|
||||||
setup(props) {
|
const data = computed(() => {
|
||||||
const settingsStore = useSettingsStore();
|
const profits = props.trades.map((trade) => trade.profit_ratio);
|
||||||
// registerTransform(ecStat.transform.histogram);
|
|
||||||
// console.log(profits);
|
|
||||||
// const data = [[]];
|
|
||||||
const binOptions = [10, 15, 20, 25, 50];
|
|
||||||
const data = computed(() => {
|
|
||||||
const profits = props.trades.map((trade) => trade.profit_ratio);
|
|
||||||
|
|
||||||
return binData(profits, settingsStore.profitDistributionBins);
|
return binData(profits, settingsStore.profitDistributionBins);
|
||||||
});
|
});
|
||||||
|
|
||||||
const chartOptions = computed((): EChartsOption => {
|
const chartOptions = computed((): EChartsOption => {
|
||||||
const chartOptionsLoc: EChartsOption = {
|
const chartOptionsLoc: EChartsOption = {
|
||||||
title: {
|
title: {
|
||||||
text: 'Profit distribution',
|
text: 'Profit distribution',
|
||||||
show: props.showTitle,
|
show: props.showTitle,
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0)',
|
||||||
|
dataset: {
|
||||||
|
source: data.value,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985',
|
||||||
},
|
},
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0)',
|
},
|
||||||
dataset: {
|
},
|
||||||
source: data.value,
|
legend: {
|
||||||
|
data: [CHART_PROFIT],
|
||||||
|
right: '5%',
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
name: 'Profit %',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 25,
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: CHART_PROFIT,
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
},
|
},
|
||||||
tooltip: {
|
nameRotate: 90,
|
||||||
trigger: 'axis',
|
nameLocation: 'middle',
|
||||||
axisPointer: {
|
nameGap: 35,
|
||||||
type: 'line',
|
position: 'left',
|
||||||
label: {
|
},
|
||||||
backgroundColor: '#6a7985',
|
],
|
||||||
},
|
// grid: {
|
||||||
},
|
// bottom: 80,
|
||||||
},
|
// },
|
||||||
legend: {
|
|
||||||
data: [CHART_PROFIT],
|
|
||||||
right: '5%',
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
name: 'Profit %',
|
|
||||||
nameLocation: 'middle',
|
|
||||||
nameGap: 25,
|
|
||||||
},
|
|
||||||
yAxis: [
|
|
||||||
{
|
|
||||||
type: 'value',
|
|
||||||
name: CHART_PROFIT,
|
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
nameRotate: 90,
|
|
||||||
nameLocation: 'middle',
|
|
||||||
nameGap: 35,
|
|
||||||
position: 'left',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// grid: {
|
|
||||||
// bottom: 80,
|
|
||||||
// },
|
|
||||||
|
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
name: CHART_PROFIT,
|
name: CHART_PROFIT,
|
||||||
animation: true,
|
animation: true,
|
||||||
encode: {
|
encode: {
|
||||||
x: 'x0',
|
x: 'x0',
|
||||||
y: 'y0',
|
y: 'y0',
|
||||||
},
|
},
|
||||||
|
|
||||||
// symbol: 'none',
|
// symbol: 'none',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
return chartOptionsLoc;
|
return chartOptionsLoc;
|
||||||
});
|
|
||||||
// console.log(chartOptions);
|
|
||||||
return { settingsStore, chartOptions, binOptions };
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -21,43 +21,30 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { timestampms } from '@/shared/formatters';
|
import { timestampms } from '@/shared/formatters';
|
||||||
import { Lock } from '@/types';
|
import { Lock } from '@/types';
|
||||||
|
|
||||||
import { showAlert } from '@/stores/alerts';
|
import { showAlert } from '@/stores/alerts';
|
||||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||||
import { defineComponent } from 'vue';
|
import { TableField } from 'bootstrap-vue-next';
|
||||||
|
const botStore = useBotStore();
|
||||||
|
|
||||||
export default defineComponent({
|
const tableFields: TableField[] = [
|
||||||
name: 'PairLockList',
|
{ key: 'pair', label: 'Pair' },
|
||||||
setup() {
|
{ key: 'lock_end_timestamp', label: 'Until', formatter: (value) => timestampms(value as number) },
|
||||||
const botStore = useBotStore();
|
{ key: 'reason', label: 'Reason' },
|
||||||
|
{ key: 'actions' },
|
||||||
|
];
|
||||||
|
|
||||||
const tableFields = [
|
const removePairLock = (item: Lock) => {
|
||||||
{ key: 'pair', label: 'Pair' },
|
console.log(item);
|
||||||
{ key: 'lock_end_timestamp', label: 'Until', formatter: 'timestampms' },
|
if (item.id !== undefined) {
|
||||||
{ key: 'reason', label: 'Reason' },
|
botStore.activeBot.deleteLock(item.id);
|
||||||
{ key: 'actions' },
|
} else {
|
||||||
];
|
showAlert('This Freqtrade version does not support deleting locks.');
|
||||||
|
}
|
||||||
const removePairLock = (item: Lock) => {
|
};
|
||||||
console.log(item);
|
|
||||||
if (item.id !== undefined) {
|
|
||||||
botStore.activeBot.deleteLock(item.id);
|
|
||||||
} else {
|
|
||||||
showAlert('This Freqtrade version does not support deleting locks.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
timestampms,
|
|
||||||
botStore,
|
|
||||||
tableFields,
|
|
||||||
removePairLock,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user