From 7b97e8a5656ec4f0dee64aadd1befaef82614bdb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Jun 2022 17:42:24 +0200 Subject: [PATCH 1/6] Add closed trades for all bots to dashboard closes #763 --- src/stores/ftbotwrapper.ts | 14 ++++++++++++++ src/stores/layout.ts | 5 ++++- src/views/Dashboard.vue | 29 ++++++++++++++++++++++++----- src/views/Trading.vue | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/stores/ftbotwrapper.ts b/src/stores/ftbotwrapper.ts index 78a7edc1..ca22e21c 100644 --- a/src/stores/ftbotwrapper.ts +++ b/src/stores/ftbotwrapper.ts @@ -97,6 +97,20 @@ export const useBotStore = defineStore('wrapper', { }); return result; }, + allClosedTradesSelectedBots: (state): Trade[] => { + const result: Trade[] = []; + Object.entries(state.botStores).forEach(([, botStore]) => { + if (botStore.isSelected) { + result.push(...botStore.trades); + } + }); + return result.sort((a, b) => + // Sort by close timestamp, then by tradeid + b.close_timestamp && a.close_timestamp + ? b.close_timestamp - a.close_timestamp + : b.trade_id - a.trade_id, + ); + }, allTradesSelectedBots: (state): ClosedTrade[] => { const result: ClosedTrade[] = []; Object.entries(state.botStores).forEach(([, botStore]) => { diff --git a/src/stores/layout.ts b/src/stores/layout.ts index 3cbc23a4..872ab798 100644 --- a/src/stores/layout.ts +++ b/src/stores/layout.ts @@ -14,6 +14,7 @@ export enum DashboardLayout { botComparison = 'g-botComparison', allOpenTrades = 'g-allOpenTrades', cumChartChart = 'g-cumChartChart', + allClosedTrades = 'g-allClosedTrades', tradesLogChart = 'g-TradesLogChart', } @@ -40,7 +41,8 @@ const DEFAULT_DASHBOARD_LAYOUT: GridItemData[] = [ { i: DashboardLayout.dailyChart, x: 8, y: 0, w: 4, h: 6 }, { i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 8, h: 6 }, { i: DashboardLayout.cumChartChart, x: 8, y: 6, w: 4, h: 6 }, - { i: DashboardLayout.tradesLogChart, x: 0, y: 12, w: 12, h: 4 }, + { i: DashboardLayout.allClosedTrades, x: 0, y: 12, w: 8, h: 6 }, + { i: DashboardLayout.tradesLogChart, x: 0, y: 18, w: 12, h: 4 }, ]; const DEFAULT_DASHBOARD_LAYOUT_SM: GridItemData[] = [ @@ -49,6 +51,7 @@ const DEFAULT_DASHBOARD_LAYOUT_SM: GridItemData[] = [ { i: DashboardLayout.dailyChart, x: 0, y: 14, w: 12, h: 6 }, { i: DashboardLayout.cumChartChart, x: 0, y: 20, w: 12, h: 6 }, { i: DashboardLayout.tradesLogChart, x: 0, y: 26, w: 12, h: 4 }, + { i: DashboardLayout.allClosedTrades, x: 0, y: 30, w: 12, h: 8 }, ]; const STORE_LAYOUTS = 'ftLayoutSettings'; diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index 880e4f9a..8e193cfc 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -57,11 +57,7 @@ drag-allow-from=".drag-header" > - + + + + + + { return findGridLayout(gridLayout.value, DashboardLayout.allOpenTrades); }); + const gridLayoutAllClosedTrades = computed((): GridItemData => { + return findGridLayout(gridLayout.value, DashboardLayout.allClosedTrades); + }); const gridLayoutCumChart = computed((): GridItemData => { return findGridLayout(gridLayout.value, DashboardLayout.cumChartChart); @@ -198,6 +216,7 @@ export default defineComponent({ gridLayoutDaily, gridLayoutBotComparison, gridLayoutAllOpenTrades, + gridLayoutAllClosedTrades, gridLayoutCumChart, gridLayoutTradesLogChart, responsiveGridLayouts, diff --git a/src/views/Trading.vue b/src/views/Trading.vue index acf76bc4..620c34c6 100644 --- a/src/views/Trading.vue +++ b/src/views/Trading.vue @@ -85,7 +85,7 @@ drag-allow-from=".card-header" > - Date: Tue, 21 Jun 2022 19:51:47 +0200 Subject: [PATCH 2/6] Add profitdistribution chart --- .../charts/ProfitDistributionChart.vue | 134 ++++++++++++++++++ src/shared/charts/binCount.ts | 19 +++ src/stores/layout.ts | 7 +- src/views/Dashboard.vue | 21 ++- tests/unit/bincount.spec.ts | 48 +++++++ 5 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 src/components/charts/ProfitDistributionChart.vue create mode 100644 src/shared/charts/binCount.ts create mode 100644 tests/unit/bincount.spec.ts diff --git a/src/components/charts/ProfitDistributionChart.vue b/src/components/charts/ProfitDistributionChart.vue new file mode 100644 index 00000000..290a56a9 --- /dev/null +++ b/src/components/charts/ProfitDistributionChart.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/src/shared/charts/binCount.ts b/src/shared/charts/binCount.ts new file mode 100644 index 00000000..0a10b317 --- /dev/null +++ b/src/shared/charts/binCount.ts @@ -0,0 +1,19 @@ +export function binData(data: number[], bins: number) { + const minimum = Math.min(...data); + const maximum = Math.max(...data); + const binSize = ((maximum - minimum) * 1.01) / bins; + // console.log(`data ranges from ${minimum} to ${maximum}, binsize ${binSize}`); + // Count occurances an array with [bucketStart, count in this bucket] + const baseBins = [...Array(bins).keys()].map((i) => [ + Math.round((minimum + i * binSize) * 1000) / 1000, + 0, + ]); + // console.log(baseBins); + for (let i = 0; i < data.length; i++) { + const index = Math.min(Math.floor((data[i] - minimum) / binSize), bins - 1); + // console.log(data[i], index) + baseBins[index][1]++; + } + + return baseBins; +} diff --git a/src/stores/layout.ts b/src/stores/layout.ts index 872ab798..8eeffe72 100644 --- a/src/stores/layout.ts +++ b/src/stores/layout.ts @@ -15,6 +15,7 @@ export enum DashboardLayout { allOpenTrades = 'g-allOpenTrades', cumChartChart = 'g-cumChartChart', allClosedTrades = 'g-allClosedTrades', + profitDistributionChart = 'g-profitDistributionChart', tradesLogChart = 'g-TradesLogChart', } @@ -42,6 +43,7 @@ const DEFAULT_DASHBOARD_LAYOUT: GridItemData[] = [ { i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 8, h: 6 }, { i: DashboardLayout.cumChartChart, x: 8, y: 6, w: 4, h: 6 }, { i: DashboardLayout.allClosedTrades, x: 0, y: 12, w: 8, h: 6 }, + { i: DashboardLayout.profitDistributionChart, x: 8, y: 12, w: 4, h: 6 }, { i: DashboardLayout.tradesLogChart, x: 0, y: 18, w: 12, h: 4 }, ]; @@ -50,8 +52,9 @@ const DEFAULT_DASHBOARD_LAYOUT_SM: GridItemData[] = [ { i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 12, h: 8 }, { i: DashboardLayout.dailyChart, x: 0, y: 14, w: 12, h: 6 }, { i: DashboardLayout.cumChartChart, x: 0, y: 20, w: 12, h: 6 }, - { i: DashboardLayout.tradesLogChart, x: 0, y: 26, w: 12, h: 4 }, - { i: DashboardLayout.allClosedTrades, x: 0, y: 30, w: 12, h: 8 }, + { i: DashboardLayout.profitDistributionChart, x: 0, y: 26, w: 12, h: 6 }, + { i: DashboardLayout.tradesLogChart, x: 0, y: 32, w: 12, h: 4 }, + { i: DashboardLayout.allClosedTrades, x: 0, y: 36, w: 12, h: 8 }, ]; const STORE_LAYOUTS = 'ftLayoutSettings'; diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index 8e193cfc..501c03be 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -93,6 +93,20 @@ /> + + + + + { return findGridLayout(gridLayout.value, DashboardLayout.cumChartChart); }); - + const gridLayoutProfitDistribution = computed((): GridItemData => { + return findGridLayout(gridLayout.value, DashboardLayout.profitDistributionChart); + }); const gridLayoutTradesLogChart = computed((): GridItemData => { return findGridLayout(gridLayout.value, DashboardLayout.tradesLogChart); }); @@ -218,6 +236,7 @@ export default defineComponent({ gridLayoutAllOpenTrades, gridLayoutAllClosedTrades, gridLayoutCumChart, + gridLayoutProfitDistribution, gridLayoutTradesLogChart, responsiveGridLayouts, }; diff --git a/tests/unit/bincount.spec.ts b/tests/unit/bincount.spec.ts new file mode 100644 index 00000000..7caf6797 --- /dev/null +++ b/tests/unit/bincount.spec.ts @@ -0,0 +1,48 @@ +import { binData } from '@/shared/charts/binCount'; + +describe.only('binCount.ts', () => { + it('Bins data as expected', () => { + const testData = [1, 1, 2, 3, 5, 6, 8, 10]; + const res = binData(testData, 3); + expect(res.length).toEqual(3); + expect(res).toEqual([ + [1, 4], + [4.03, 2], + [7.06, 2], + ]); + expect(res.map((v) => v[1]).reduce((a, b) => a + b)).toEqual(testData.length); + const res1 = binData(testData, 5); + // expect(res1.length).toEqual(5); + expect(res1).toEqual([ + [1, 3], + [2.818, 1], + [4.636, 2], + [6.454, 1], + [8.272, 1], + ]); + expect(res1.map((v) => v[1]).reduce((a, b) => a + b)).toEqual(testData.length); + }); + + it('Bins data with negatives', () => { + const testData = [1, 1, 2, 3, 5, 6, 8, -1, -3, -5, -4]; + const res = binData(testData, 3); + expect(res.length).toEqual(3); + expect(res.map((v) => v[1]).reduce((a, b) => a + b)).toEqual(testData.length); + expect(res).toEqual([ + [-5, 4], + [-0.623, 4], + [3.753, 3], + ]); + }); + it('Bins data performant', () => { + const randomSize = 20000; + const randomData = Array.from({ length: randomSize }, () => Math.floor(Math.random() * 10)); + const startTime = performance.now(); + const res = binData(randomData, 5); + + const endTime = performance.now(); + expect(endTime - startTime).toBeLessThan(20); + + expect(res.map((v) => v[1]).reduce((a, b) => a + b)).toEqual(randomData.length); + }); +}); From 261b3fb947f28fa9dc2e1a6a1f473c725069deff Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 2 Sep 2022 20:37:18 +0200 Subject: [PATCH 3/6] Convert profitdistro chart to use computed props --- src/components/charts/ProfitDistributionChart.vue | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/charts/ProfitDistributionChart.vue b/src/components/charts/ProfitDistributionChart.vue index 290a56a9..1124019b 100644 --- a/src/components/charts/ProfitDistributionChart.vue +++ b/src/components/charts/ProfitDistributionChart.vue @@ -50,13 +50,15 @@ export default defineComponent({ console.log('setup start'); const settingsStore = useSettingsStore(); // registerTransform(ecStat.transform.histogram); - const profits = props.trades.map((trade) => trade.profit_ratio); // console.log(profits); // const data = [[]]; const bins = 10; - const data = binData(profits, bins); - console.log(profits, data); + const data = computed(() => { + const profits = props.trades.map((trade) => trade.profit_ratio); + + return binData(profits, bins); + }); const chartOptions = computed((): EChartsOption => { const chartOptionsLoc: EChartsOption = { @@ -66,7 +68,7 @@ export default defineComponent({ }, backgroundColor: 'rgba(0, 0, 0, 0)', dataset: { - source: data, + source: data.value, }, tooltip: { trigger: 'axis', From 4fdd72045bc430b11e917ad39d820f4d051c7758 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 14 Sep 2022 19:55:14 +0200 Subject: [PATCH 4/6] Add more options to profitdistributionchart --- .../charts/ProfitDistributionChart.vue | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/components/charts/ProfitDistributionChart.vue b/src/components/charts/ProfitDistributionChart.vue index 1124019b..70fb9670 100644 --- a/src/components/charts/ProfitDistributionChart.vue +++ b/src/components/charts/ProfitDistributionChart.vue @@ -1,5 +1,19 @@ From 43d6ae38846b74699c2997aefe64fa91c891881b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 14 Sep 2022 20:14:20 +0200 Subject: [PATCH 5/6] Add Profit-distribution plot to backtesting --- src/components/charts/ProfitDistributionChart.vue | 10 +++++----- src/views/Backtesting.vue | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/charts/ProfitDistributionChart.vue b/src/components/charts/ProfitDistributionChart.vue index 70fb9670..5597f5db 100644 --- a/src/components/charts/ProfitDistributionChart.vue +++ b/src/components/charts/ProfitDistributionChart.vue @@ -1,10 +1,11 @@