frequi_origin/src/components/charts/CandleChartContainer.vue

259 lines
8.0 KiB
Vue
Raw Normal View History

2020-08-08 13:37:18 +00:00
<template>
2021-06-22 19:04:33 +00:00
<div class="d-flex h-100">
<div class="flex-fill container-fluid flex-column align-items-stretch d-flex h-100">
<b-modal
v-if="plotConfigModal"
2021-06-22 19:04:33 +00:00
id="plotConfiguratorModal"
title="Plot Configurator"
ok-only
hide-backdrop
button-size="sm"
>
<PlotConfigurator :columns="datasetColumns" />
2021-06-22 19:04:33 +00:00
</b-modal>
<div class="row mr-0">
2021-11-02 06:11:02 +00:00
<div class="ml-2 d-flex flex-wrap flex-md-nowrap align-items-center">
<span class="ml-2 text-nowrap">{{ strategyName }} | {{ timeframe || '' }}</span>
<v-select
v-model="pair"
class="ml-2"
:options="availablePairs"
2021-11-02 06:11:02 +00:00
style="min-width: 7em"
size="sm"
:clearable="false"
2022-07-16 20:01:50 +00:00
@input="refresh"
>
</v-select>
<b-button class="ml-2" :disabled="!!!pair" size="sm" @click="refresh">&#x21bb;</b-button>
2022-04-02 17:23:32 +00:00
<small v-if="dataset" class="ml-2 text-nowrap" title="Long entry signals"
>Long signals: {{ dataset.enter_long_signals || dataset.buy_signals }}</small
>
2022-04-02 17:23:32 +00:00
<small v-if="dataset" class="ml-2 text-nowrap" title="Long exit signals"
>Long exit: {{ dataset.exit_long_signals || dataset.sell_signals }}</small
>
2021-11-20 19:11:54 +00:00
<small v-if="dataset && dataset.enter_short_signals" class="ml-2 text-nowrap"
>Short entries: {{ dataset.enter_short_signals }}</small
>
<small v-if="dataset && dataset.exit_short_signals" class="ml-2 text-nowrap"
>Short exits: {{ dataset.exit_short_signals }}</small
>
2021-06-22 19:04:33 +00:00
</div>
2022-10-30 13:26:23 +00:00
<div class="ms-auto d-flex align-items-center">
2022-07-11 14:33:47 +00:00
<b-form-checkbox v-model="settingsStore.useHeikinAshiCandles"
>Heikin Ashi</b-form-checkbox
>
2022-03-11 06:48:39 +00:00
<div class="ml-2">
<b-form-select
v-model="plotStore.plotConfigName"
2022-11-01 13:10:59 +00:00
:options="plotStore.availablePlotConfigNames"
2022-03-11 06:48:39 +00:00
size="sm"
2022-11-01 13:45:37 +00:00
@change="plotStore.plotConfigChanged"
2022-03-11 06:48:39 +00:00
>
</b-form-select>
2022-03-11 06:48:39 +00:00
</div>
2021-06-22 19:04:33 +00:00
2022-03-11 06:48:39 +00:00
<div class="ml-2 mr-0 mr-md-1">
<b-button size="sm" title="Plot configurator" @click="showConfigurator">
&#9881;
</b-button>
</div>
2021-06-22 19:04:33 +00:00
</div>
2020-09-27 07:24:12 +00:00
</div>
2021-06-22 19:04:33 +00:00
<div class="row mr-1 ml-1 h-100">
<CandleChart
v-if="hasDataset"
:dataset="dataset"
:trades="trades"
2022-11-01 13:45:37 +00:00
:plot-config="plotStore.plotConfig"
2022-07-11 14:33:47 +00:00
:heikin-ashi="settingsStore.useHeikinAshiCandles"
2022-04-17 07:28:00 +00:00
:use-u-t-c="settingsStore.timezone === 'UTC'"
:theme="settingsStore.chartTheme"
2022-08-01 22:50:36 +00:00
:slider-position="sliderPosition"
2020-08-08 13:57:36 +00:00
>
2021-06-22 19:04:33 +00:00
</CandleChart>
2022-03-03 18:37:38 +00:00
<div v-else class="m-auto">
2022-03-03 18:46:42 +00:00
<b-spinner v-if="isLoadingDataset" label="Spinning" />
2022-03-03 18:37:38 +00:00
2022-03-03 18:46:42 +00:00
<div v-else style="font-size: 1.5rem">
2022-03-03 18:37:38 +00:00
{{ noDatasetText }}
</div>
</div>
2020-08-08 13:37:18 +00:00
</div>
</div>
2021-06-22 19:04:33 +00:00
<transition name="fade" mode="in-out">
<div v-if="!plotConfigModal" v-show="showPlotConfig" class="w-25 config-sidebar">
<PlotConfigurator :columns="datasetColumns" :as-modal="false" />
2021-06-22 19:04:33 +00:00
</div>
</transition>
2020-08-08 13:37:18 +00:00
</div>
</template>
<script lang="ts">
2022-11-01 13:45:37 +00:00
import { Trade, PairHistory, LoadingStatus, ChartSliderPosition } from '@/types';
import CandleChart from '@/components/charts/CandleChart.vue';
import PlotConfigurator from '@/components/charts/PlotConfigurator.vue';
import vSelect from 'vue-select';
2022-04-13 19:28:04 +00:00
import { useSettingsStore } from '@/stores/settings';
2022-11-01 13:10:59 +00:00
import { usePlotConfigStore } from '@/stores/plotConfig';
2020-08-08 13:57:36 +00:00
2022-07-07 18:44:19 +00:00
import { defineComponent, ref, computed, onMounted, watch, getCurrentInstance } from 'vue';
2022-04-18 11:43:55 +00:00
import { useBotStore } from '@/stores/ftbotwrapper';
2022-04-17 07:28:00 +00:00
export default defineComponent({
name: 'CandleChartContainer',
components: { CandleChart, PlotConfigurator, vSelect },
props: {
trades: { required: false, default: () => [], type: Array as () => Trade[] },
2022-04-17 07:28:00 +00:00
availablePairs: { required: true, type: Array as () => string[] },
timeframe: { required: true, type: String },
historicView: { required: false, default: false, type: Boolean },
plotConfigModal: { required: false, default: true, type: Boolean },
/** Only required if historicView is true */
timerange: { required: false, default: '', type: String },
/** Only required if historicView is true */
strategy: { required: false, default: '', type: String },
2022-08-01 22:50:36 +00:00
sliderPosition: {
required: false,
type: Object as () => ChartSliderPosition,
default: () => undefined,
},
2022-04-17 07:28:00 +00:00
},
2022-07-07 18:44:19 +00:00
setup(props) {
const root = getCurrentInstance();
2022-04-17 07:28:00 +00:00
const settingsStore = useSettingsStore();
2022-04-18 11:43:55 +00:00
const botStore = useBotStore();
2022-11-01 13:10:59 +00:00
const plotStore = usePlotConfigStore();
2022-04-18 17:46:53 +00:00
2022-04-17 07:28:00 +00:00
const pair = ref('');
const showPlotConfig = ref(props.plotConfigModal);
const dataset = computed((): PairHistory => {
if (props.historicView) {
2022-04-18 11:43:55 +00:00
return botStore.activeBot.history[`${pair.value}__${props.timeframe}`]?.data;
2022-04-17 07:28:00 +00:00
}
2022-04-18 11:43:55 +00:00
return botStore.activeBot.candleData[`${pair.value}__${props.timeframe}`]?.data;
2022-04-17 07:28:00 +00:00
});
const strategyName = computed(() => props.strategy || dataset.value?.strategy || '');
const datasetColumns = computed(() => (dataset.value ? dataset.value.columns : []));
const hasDataset = computed(() => !!dataset.value);
const isLoadingDataset = computed((): boolean => {
if (props.historicView) {
2022-04-18 11:43:55 +00:00
return botStore.activeBot.historyStatus === LoadingStatus.loading;
2022-04-17 07:28:00 +00:00
}
2022-03-03 18:37:38 +00:00
2022-04-18 11:43:55 +00:00
return botStore.activeBot.candleDataStatus === LoadingStatus.loading;
2022-04-17 07:28:00 +00:00
});
const noDatasetText = computed((): string => {
2022-04-18 11:43:55 +00:00
const status = props.historicView
? botStore.activeBot.historyStatus
: botStore.activeBot.candleDataStatus;
2022-03-03 18:37:38 +00:00
2022-04-17 07:28:00 +00:00
switch (status) {
2022-04-18 11:43:55 +00:00
case LoadingStatus.loading:
2022-04-17 07:28:00 +00:00
return 'Loading...';
2022-03-03 18:37:38 +00:00
2022-04-18 11:43:55 +00:00
case LoadingStatus.success:
2022-04-17 07:28:00 +00:00
return 'No data available';
2020-09-27 07:37:07 +00:00
2022-04-18 11:43:55 +00:00
case LoadingStatus.error:
2022-04-17 07:28:00 +00:00
return 'Failed to load data';
2022-04-13 19:28:04 +00:00
2022-04-17 07:28:00 +00:00
default:
return 'Unknown';
}
2022-04-13 19:28:04 +00:00
});
2022-04-17 07:28:00 +00:00
const showConfigurator = () => {
if (props.plotConfigModal) {
2022-07-09 18:04:22 +00:00
root?.proxy.$bvModal.show('plotConfiguratorModal');
2022-04-17 07:28:00 +00:00
} else {
showPlotConfig.value = !showPlotConfig.value;
}
};
const refresh = () => {
2022-07-16 20:01:50 +00:00
console.log('refresh', pair.value, props.timeframe);
2022-04-17 07:28:00 +00:00
if (pair.value && props.timeframe) {
if (props.historicView) {
2022-04-18 11:43:55 +00:00
botStore.activeBot.getPairHistory({
2022-04-17 07:28:00 +00:00
pair: pair.value,
timeframe: props.timeframe,
timerange: props.timerange,
strategy: props.strategy,
});
} else {
2022-04-18 11:43:55 +00:00
botStore.activeBot.getPairCandles({
pair: pair.value,
timeframe: props.timeframe,
limit: 500,
});
2022-04-17 07:28:00 +00:00
}
}
};
2020-08-08 13:57:36 +00:00
2022-04-18 17:46:53 +00:00
watch(
() => props.availablePairs,
() => {
if (!props.availablePairs.find((p) => p === pair.value)) {
[pair.value] = props.availablePairs;
refresh();
}
},
);
2020-08-08 13:37:18 +00:00
2022-04-18 17:46:53 +00:00
watch(
() => botStore.activeBot.selectedPair,
() => {
pair.value = botStore.activeBot.selectedPair;
refresh();
},
);
2022-04-17 07:28:00 +00:00
onMounted(() => {
2022-04-18 11:43:55 +00:00
if (botStore.activeBot.selectedPair) {
pair.value = botStore.activeBot.selectedPair;
2022-04-17 07:28:00 +00:00
} else if (props.availablePairs.length > 0) {
[pair.value] = props.availablePairs;
}
2022-11-01 13:45:37 +00:00
plotStore.plotConfigChanged();
2022-04-17 07:28:00 +00:00
if (!hasDataset) {
refresh();
}
});
2020-10-31 07:47:07 +00:00
2022-04-17 07:28:00 +00:00
return {
2022-04-18 11:43:55 +00:00
botStore,
settingsStore,
2022-11-01 13:10:59 +00:00
plotStore,
2022-04-17 07:28:00 +00:00
history,
dataset,
strategyName,
datasetColumns,
isLoadingDataset,
noDatasetText,
hasDataset,
showPlotConfig,
showConfigurator,
refresh,
pair,
};
},
});
2020-08-08 13:37:18 +00:00
</script>
2021-06-22 19:04:33 +00:00
<style scoped lang="scss">
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>