chore: update block-order in components

script before template.
This commit is contained in:
Matthias 2024-07-30 06:19:12 +02:00
parent e6273955f2
commit 8b40c2a862
15 changed files with 574 additions and 574 deletions

View File

@ -1,12 +1,3 @@
<template>
<div id="app" class="d-flex flex-column dvh-100" :style="colorStore.cssVars">
<NavBar />
<BaseAlert></BaseAlert>
<BodyLayout class="flex-fill overflow-auto" />
<NavFooter />
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { useSettingsStore } from './stores/settings'; import { useSettingsStore } from './stores/settings';
import { useColorStore } from './stores/colors'; import { useColorStore } from './stores/colors';
@ -25,6 +16,15 @@ watch(
); );
</script> </script>
<template>
<div id="app" class="d-flex flex-column dvh-100" :style="colorStore.cssVars">
<NavBar />
<BaseAlert></BaseAlert>
<BodyLayout class="flex-fill overflow-auto" />
<NavFooter />
</div>
</template>
<style scoped> <style scoped>
#app { #app {
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;

View File

@ -1,3 +1,35 @@
<script setup lang="ts">
import { useBotStore } from '@/stores/ftbotwrapper';
import { BotDescriptor } from '@/types';
import type { CheckboxValue } from 'bootstrap-vue-next';
const props = defineProps({
bot: { required: true, type: Object as () => BotDescriptor },
noButtons: { default: false, type: Boolean },
});
defineEmits<{ edit: []; editLogin: [] }>();
const botStore = useBotStore();
const changeEvent = (v: CheckboxValue) => {
botStore.botStores[props.bot.botId].setAutoRefresh(v as boolean);
};
const botRemoveModalVisible = ref(false);
const confirmRemoveBot = () => {
botRemoveModalVisible.value = false;
botStore.removeBot(props.bot.botId);
console.log('removing bot.');
};
const autoRefreshLoc = computed({
get() {
return botStore.botStores[props.bot.botId].autoRefresh;
},
set() {
// pass
},
});
</script>
<template> <template>
<div v-if="bot" class="d-flex align-items-center justify-content-between w-100"> <div v-if="bot" class="d-flex align-items-center justify-content-between w-100">
<span class="me-2">{{ bot.botName || bot.botId }}</span> <span class="me-2">{{ bot.botName || bot.botId }}</span>
@ -54,38 +86,6 @@
</div> </div>
</template> </template>
<script setup lang="ts">
import { useBotStore } from '@/stores/ftbotwrapper';
import { BotDescriptor } from '@/types';
import type { CheckboxValue } from 'bootstrap-vue-next';
const props = defineProps({
bot: { required: true, type: Object as () => BotDescriptor },
noButtons: { default: false, type: Boolean },
});
defineEmits<{ edit: []; editLogin: [] }>();
const botStore = useBotStore();
const changeEvent = (v: CheckboxValue) => {
botStore.botStores[props.bot.botId].setAutoRefresh(v as boolean);
};
const botRemoveModalVisible = ref(false);
const confirmRemoveBot = () => {
botRemoveModalVisible.value = false;
botStore.removeBot(props.bot.botId);
console.log('removing bot.');
};
const autoRefreshLoc = computed({
get() {
return botStore.botStores[props.bot.botId].autoRefresh;
},
set() {
// pass
},
});
</script>
<style scoped lang="scss"> <style scoped lang="scss">
.form-switch { .form-switch {
padding-left: 0; padding-left: 0;

View File

@ -1,39 +1,3 @@
<template>
<div v-if="botStore.botCount > 0">
<h3 v-if="!small">Available bots</h3>
<BListGroup ref="sortContainer">
<BListGroupItem
v-for="bot in botListComp"
:key="bot.botId"
:active="bot.botId === botStore.selectedBot"
button
:title="`${bot.botId} - ${bot.botName} - ${bot.botUrl} - ${
botStore.botStores[bot.botId].isBotLoggedIn ? '' : 'Login info expired!'
}`"
class="d-flex"
@click="botStore.selectBot(bot.botId)"
>
<i-mdi-reorder-horizontal v-if="!small" class="handle me-2 fs-4" />
<BotRename
v-if="editingBots.includes(bot.botId)"
:bot="bot"
@saved="stopEditBot(bot.botId)"
@cancelled="stopEditBot(bot.botId)"
/>
<BotEntry
v-else
:bot="bot"
:no-buttons="small"
@edit="editBot(bot.botId)"
@edit-login="editBotLogin(bot.botId)"
/>
</BListGroupItem>
</BListGroup>
<LoginModal v-if="!small" ref="loginModal" class="mt-2" login-text="Add new bot" />
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import LoginModal from '@/components/LoginModal.vue'; import LoginModal from '@/components/LoginModal.vue';
@ -87,3 +51,39 @@ const stopEditBot = (botId: string) => {
editingBots.value.splice(editingBots.value.indexOf(botId), 1); editingBots.value.splice(editingBots.value.indexOf(botId), 1);
}; };
</script> </script>
<template>
<div v-if="botStore.botCount > 0">
<h3 v-if="!small">Available bots</h3>
<BListGroup ref="sortContainer">
<BListGroupItem
v-for="bot in botListComp"
:key="bot.botId"
:active="bot.botId === botStore.selectedBot"
button
:title="`${bot.botId} - ${bot.botName} - ${bot.botUrl} - ${
botStore.botStores[bot.botId].isBotLoggedIn ? '' : 'Login info expired!'
}`"
class="d-flex"
@click="botStore.selectBot(bot.botId)"
>
<i-mdi-reorder-horizontal v-if="!small" class="handle me-2 fs-4" />
<BotRename
v-if="editingBots.includes(bot.botId)"
:bot="bot"
@saved="stopEditBot(bot.botId)"
@cancelled="stopEditBot(bot.botId)"
/>
<BotEntry
v-else
:bot="bot"
:no-buttons="small"
@edit="editBot(bot.botId)"
@edit-login="editBotLogin(bot.botId)"
/>
</BListGroupItem>
</BListGroup>
<LoginModal v-if="!small" ref="loginModal" class="mt-2" login-text="Add new bot" />
</div>
</template>

View File

@ -1,87 +1,3 @@
<template>
<div>
<form ref="formRef" novalidate @submit.stop.prevent="handleSubmit" @reset="handleReset">
<BFormGroup label="Bot Name" label-for="name-input">
<BFormInput
id="name-input"
v-model="auth.botName"
placeholder="Bot Name"
@keydown.enter="handleOk"
></BFormInput>
</BFormGroup>
<BFormGroup
:state="urlState"
label="API Url"
label-for="url-input"
invalid-feedback="API Url required"
>
<BFormInput
id="url-input"
v-model="auth.url"
required
trim
:state="urlState"
@keydown.enter="handleOk"
></BFormInput>
<BAlert
v-if="urlDuplicate"
class="mt-2 p-1 alert-wrap"
:model-value="true"
variant="warning"
>
This URL is already in use by another bot.
</BAlert>
</BFormGroup>
<BFormGroup
:state="nameState"
label="Username"
label-for="username-input"
invalid-feedback="Name and Password are required."
>
<BFormInput
id="username-input"
v-model="auth.username"
required
placeholder="Freqtrader"
:state="nameState"
@keydown.enter="handleOk"
></BFormInput>
</BFormGroup>
<BFormGroup
label="Password"
label-for="password-input"
invalid-feedback="Invalid Password"
:state="pwdState"
>
<BFormInput
id="password-input"
v-model="auth.password"
required
type="password"
:state="pwdState"
@keydown.enter="handleOk"
></BFormInput>
</BFormGroup>
<div>
<BAlert v-if="errorMessage" class="alert-wrap" :model-value="true" variant="warning">
{{ errorMessage }}
<br />
<span v-if="errorMessageCORS"
>Please also check your bot's CORS configuration:
<a href="https://www.freqtrade.io/en/latest/rest-api/#cors"
>Freqtrade CORS documentation</a
></span
>
</BAlert>
</div>
<div v-if="inModal === false" class="float-end">
<BButton class="me-2" type="reset" variant="danger">Reset</BButton>
<BButton type="submit" variant="primary">Submit</BButton>
</div>
</form>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { useUserService } from '@/shared/userService'; import { useUserService } from '@/shared/userService';
import { AuthPayload, AuthStorageWithBotId } from '@/types'; import { AuthPayload, AuthStorageWithBotId } from '@/types';
@ -236,6 +152,90 @@ defineExpose({
}); });
</script> </script>
<template>
<div>
<form ref="formRef" novalidate @submit.stop.prevent="handleSubmit" @reset="handleReset">
<BFormGroup label="Bot Name" label-for="name-input">
<BFormInput
id="name-input"
v-model="auth.botName"
placeholder="Bot Name"
@keydown.enter="handleOk"
></BFormInput>
</BFormGroup>
<BFormGroup
:state="urlState"
label="API Url"
label-for="url-input"
invalid-feedback="API Url required"
>
<BFormInput
id="url-input"
v-model="auth.url"
required
trim
:state="urlState"
@keydown.enter="handleOk"
></BFormInput>
<BAlert
v-if="urlDuplicate"
class="mt-2 p-1 alert-wrap"
:model-value="true"
variant="warning"
>
This URL is already in use by another bot.
</BAlert>
</BFormGroup>
<BFormGroup
:state="nameState"
label="Username"
label-for="username-input"
invalid-feedback="Name and Password are required."
>
<BFormInput
id="username-input"
v-model="auth.username"
required
placeholder="Freqtrader"
:state="nameState"
@keydown.enter="handleOk"
></BFormInput>
</BFormGroup>
<BFormGroup
label="Password"
label-for="password-input"
invalid-feedback="Invalid Password"
:state="pwdState"
>
<BFormInput
id="password-input"
v-model="auth.password"
required
type="password"
:state="pwdState"
@keydown.enter="handleOk"
></BFormInput>
</BFormGroup>
<div>
<BAlert v-if="errorMessage" class="alert-wrap" :model-value="true" variant="warning">
{{ errorMessage }}
<br />
<span v-if="errorMessageCORS"
>Please also check your bot's CORS configuration:
<a href="https://www.freqtrade.io/en/latest/rest-api/#cors"
>Freqtrade CORS documentation</a
></span
>
</BAlert>
</div>
<div v-if="inModal === false" class="float-end">
<BButton class="me-2" type="reset" variant="danger">Reset</BButton>
<BButton type="submit" variant="primary">Submit</BButton>
</div>
</form>
</div>
</template>
<style scoped lang="scss"> <style scoped lang="scss">
.alert-wrap { .alert-wrap {
white-space: pre-wrap; white-space: pre-wrap;

View File

@ -1,26 +1,3 @@
<template>
<form class="d-flex" @submit.prevent="save">
<BFormInput
v-model="newName"
size="sm"
class="w-100"
placeholder="Bot name"
style="border-style: solid; border-width: 1px"
autofocus
/>
<div class="d-flex ms-2 no-min-w">
<BButton type="submit" size="sm" title="Save" class="no-min-w">
<i-mdi-check />
</BButton>
<BButton class="ms-1 no-min-w" size="sm" title="Cancel" @click="$emit('cancelled')">
<i-mdi-close />
</BButton>
</div>
</form>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { useBotStore } from '@/stores/ftbotwrapper'; import { useBotStore } from '@/stores/ftbotwrapper';
import { BotDescriptor } from '@/types'; import { BotDescriptor } from '@/types';
@ -45,3 +22,26 @@ const save = () => {
emit('saved'); emit('saved');
}; };
</script> </script>
<template>
<form class="d-flex" @submit.prevent="save">
<BFormInput
v-model="newName"
size="sm"
class="w-100"
placeholder="Bot name"
style="border-style: solid; border-width: 1px"
autofocus
/>
<div class="d-flex ms-2 no-min-w">
<BButton type="submit" size="sm" title="Save" class="no-min-w">
<i-mdi-check />
</BButton>
<BButton class="ms-1 no-min-w" size="sm" title="Cancel" @click="$emit('cancelled')">
<i-mdi-close />
</BButton>
</div>
</form>
</template>

View File

@ -1,22 +1,3 @@
<template>
<div>
<BButton @click="openLoginModal()"><i-mdi-login class="me-1" />{{ loginText }}</BButton>
<BModal
id="modal-prevent-closing"
v-model="loginViewOpen"
title="Login to your bot"
@ok="handleOk"
>
<BotLogin
ref="loginForm"
in-modal
:existing-auth="loginInfo"
@login-result="handleLoginResult"
/>
</BModal>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import BotLogin from '@/components/BotLogin.vue'; import BotLogin from '@/components/BotLogin.vue';
import { AuthStorageWithBotId } from '@/types'; import { AuthStorageWithBotId } from '@/types';
@ -48,4 +29,23 @@ defineExpose({
}); });
</script> </script>
<template>
<div>
<BButton @click="openLoginModal()"><i-mdi-login class="me-1" />{{ loginText }}</BButton>
<BModal
id="modal-prevent-closing"
v-model="loginViewOpen"
title="Login to your bot"
@ok="handleOk"
>
<BotLogin
ref="loginForm"
in-modal
:existing-auth="loginInfo"
@login-result="handleLoginResult"
/>
</BModal>
</div>
</template>
<style scoped></style> <style scoped></style>

View File

@ -1,9 +1,3 @@
<template>
<BNavItem @click="toggleNight">
<i-mdi-brightness-6 />
</BNavItem>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
import { useColorMode } from 'bootstrap-vue-next'; import { useColorMode } from 'bootstrap-vue-next';
@ -43,4 +37,10 @@ const toggleNight = () => {
}; };
</script> </script>
<template>
<BNavItem @click="toggleNight">
<i-mdi-brightness-6 />
</BNavItem>
</template>
<style scoped></style> <style scoped></style>

View File

@ -1,14 +1,3 @@
<template>
<ECharts
v-if="currencies"
ref="balanceChart"
:option="balanceChartOptions"
:theme="settingsStore.chartTheme"
:style="{ height: width * 0.6 + 'px' }"
autoresize
/>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { EChartsOption } from 'echarts'; import { EChartsOption } from 'echarts';
import ECharts from 'vue-echarts'; import ECharts from 'vue-echarts';
@ -95,6 +84,17 @@ const balanceChartOptions = computed((): EChartsOption => {
}); });
</script> </script>
<template>
<ECharts
v-if="currencies"
ref="balanceChart"
:option="balanceChartOptions"
:theme="settingsStore.chartTheme"
:style="{ height: width * 0.6 + 'px' }"
autoresize
/>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
.echarts { .echarts {
min-height: 20px; min-height: 20px;

View File

@ -1,9 +1,3 @@
<template>
<div class="chart-wrapper">
<ECharts v-if="hasData" ref="candleChart" :theme="theme" autoresize manual-update />
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { import {
ChartSliderPosition, ChartSliderPosition,
@ -725,6 +719,12 @@ watch(
); );
</script> </script>
<template>
<div class="chart-wrapper">
<ECharts v-if="hasData" ref="candleChart" :theme="theme" autoresize manual-update />
</div>
</template>
<style scoped> <style scoped>
.chart-wrapper { .chart-wrapper {
width: 100%; width: 100%;

View File

@ -1,110 +1,3 @@
<template>
<div class="d-flex h-100">
<div class="flex-fill w-100 flex-column align-items-stretch d-flex h-100">
<div class="d-flex me-0">
<div class="ms-1 ms-md-2 d-flex flex-wrap flex-md-nowrap align-items-center w-auto">
<span class="ms-md-2 text-nowrap">{{ strategyName }} | {{ timeframe || '' }}</span>
<VSelect
v-model="botStore.activeBot.plotPair"
class="ms-md-2"
:options="availablePairs"
style="min-width: 7em"
size="sm"
:clearable="false"
@input="refresh"
>
</VSelect>
<BButton
title="Refresh chart"
class="ms-2"
:disabled="!!!botStore.activeBot.plotPair || isLoadingDataset"
size="sm"
@click="refresh"
>
<i-mdi-refresh />
</BButton>
<BSpinner v-if="isLoadingDataset" small class="ms-2" label="Spinning" />
<div class="d-flex flex-column">
<div class="d-flex flex-row flex-wrap">
<small v-if="dataset" class="ms-2 text-nowrap" title="Long entry signals"
>Long entries: {{ dataset.enter_long_signals || dataset.buy_signals }}</small
>
<small v-if="dataset" class="ms-2 text-nowrap" title="Long exit signals"
>Long exit: {{ dataset.exit_long_signals || dataset.sell_signals }}</small
>
</div>
<div class="d-flex flex-row flex-wrap">
<small v-if="dataset && dataset.enter_short_signals" class="ms-2 text-nowrap"
>Short entries: {{ dataset.enter_short_signals }}</small
>
<small v-if="dataset && dataset.exit_short_signals" class="ms-2 text-nowrap"
>Short exits: {{ dataset.exit_short_signals }}</small
>
</div>
</div>
</div>
<div class="ms-auto d-flex align-items-center w-auto">
<BFormCheckbox v-model="settingsStore.useHeikinAshiCandles">
<small class="text-nowrap">Heikin Ashi</small>
</BFormCheckbox>
<div class="ms-2">
<PlotConfigSelect></PlotConfigSelect>
</div>
<div class="ms-2 me-0 me-md-1">
<BButton size="sm" title="Plot configurator" @click="showConfigurator">
<i-mdi-cog width="12" height="12" />
</BButton>
</div>
</div>
</div>
<div class="h-100 w-100 d-flex">
<div class="flex-grow-1">
<CandleChart
v-if="hasDataset"
:dataset="dataset"
:trades="trades"
:plot-config="plotStore.plotConfig"
:heikin-ashi="settingsStore.useHeikinAshiCandles"
:use-u-t-c="settingsStore.timezone === 'UTC'"
:theme="settingsStore.chartTheme"
:slider-position="sliderPosition"
:color-up="colorStore.colorUp"
:color-down="colorStore.colorDown"
:label-side="settingsStore.chartLabelSide"
/>
<div v-else class="m-auto">
<BSpinner v-if="isLoadingDataset" label="Spinning" />
<div v-else style="font-size: 1.5rem">
{{ noDatasetText }}
</div>
<p v-if="botStore.activeBot.historyTakesLonger">
This is taking longer than expected ... Hold on ...
</p>
</div>
</div>
<Transition name="fade">
<div v-if="!plotConfigModal" v-show="showPlotConfig" class="w-25">
<PlotConfigurator :columns="datasetColumns" :is-visible="showPlotConfig ?? false" />
</div>
</Transition>
</div>
</div>
<BModal
v-if="plotConfigModal"
id="plotConfiguratorModal"
v-model="showPlotConfigModal"
title="Plot Configurator"
ok-only
hide-backdrop
>
<PlotConfigurator :is-visible="showPlotConfigModal" :columns="datasetColumns" />
</BModal>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { usePlotConfigStore } from '@/stores/plotConfig'; import { usePlotConfigStore } from '@/stores/plotConfig';
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
@ -266,6 +159,113 @@ onMounted(() => {
}); });
</script> </script>
<template>
<div class="d-flex h-100">
<div class="flex-fill w-100 flex-column align-items-stretch d-flex h-100">
<div class="d-flex me-0">
<div class="ms-1 ms-md-2 d-flex flex-wrap flex-md-nowrap align-items-center w-auto">
<span class="ms-md-2 text-nowrap">{{ strategyName }} | {{ timeframe || '' }}</span>
<VSelect
v-model="botStore.activeBot.plotPair"
class="ms-md-2"
:options="availablePairs"
style="min-width: 7em"
size="sm"
:clearable="false"
@input="refresh"
>
</VSelect>
<BButton
title="Refresh chart"
class="ms-2"
:disabled="!!!botStore.activeBot.plotPair || isLoadingDataset"
size="sm"
@click="refresh"
>
<i-mdi-refresh />
</BButton>
<BSpinner v-if="isLoadingDataset" small class="ms-2" label="Spinning" />
<div class="d-flex flex-column">
<div class="d-flex flex-row flex-wrap">
<small v-if="dataset" class="ms-2 text-nowrap" title="Long entry signals"
>Long entries: {{ dataset.enter_long_signals || dataset.buy_signals }}</small
>
<small v-if="dataset" class="ms-2 text-nowrap" title="Long exit signals"
>Long exit: {{ dataset.exit_long_signals || dataset.sell_signals }}</small
>
</div>
<div class="d-flex flex-row flex-wrap">
<small v-if="dataset && dataset.enter_short_signals" class="ms-2 text-nowrap"
>Short entries: {{ dataset.enter_short_signals }}</small
>
<small v-if="dataset && dataset.exit_short_signals" class="ms-2 text-nowrap"
>Short exits: {{ dataset.exit_short_signals }}</small
>
</div>
</div>
</div>
<div class="ms-auto d-flex align-items-center w-auto">
<BFormCheckbox v-model="settingsStore.useHeikinAshiCandles">
<small class="text-nowrap">Heikin Ashi</small>
</BFormCheckbox>
<div class="ms-2">
<PlotConfigSelect></PlotConfigSelect>
</div>
<div class="ms-2 me-0 me-md-1">
<BButton size="sm" title="Plot configurator" @click="showConfigurator">
<i-mdi-cog width="12" height="12" />
</BButton>
</div>
</div>
</div>
<div class="h-100 w-100 d-flex">
<div class="flex-grow-1">
<CandleChart
v-if="hasDataset"
:dataset="dataset"
:trades="trades"
:plot-config="plotStore.plotConfig"
:heikin-ashi="settingsStore.useHeikinAshiCandles"
:use-u-t-c="settingsStore.timezone === 'UTC'"
:theme="settingsStore.chartTheme"
:slider-position="sliderPosition"
:color-up="colorStore.colorUp"
:color-down="colorStore.colorDown"
:label-side="settingsStore.chartLabelSide"
/>
<div v-else class="m-auto">
<BSpinner v-if="isLoadingDataset" label="Spinning" />
<div v-else style="font-size: 1.5rem">
{{ noDatasetText }}
</div>
<p v-if="botStore.activeBot.historyTakesLonger">
This is taking longer than expected ... Hold on ...
</p>
</div>
</div>
<Transition name="fade">
<div v-if="!plotConfigModal" v-show="showPlotConfig" class="w-25">
<PlotConfigurator :columns="datasetColumns" :is-visible="showPlotConfig ?? false" />
</div>
</Transition>
</div>
</div>
<BModal
v-if="plotConfigModal"
id="plotConfiguratorModal"
v-model="showPlotConfigModal"
title="Plot Configurator"
ok-only
hide-backdrop
>
<PlotConfigurator :is-visible="showPlotConfigModal" :columns="datasetColumns" />
</BModal>
</div>
</template>
<style scoped lang="scss"> <style scoped lang="scss">
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {

View File

@ -1,13 +1,3 @@
<template>
<ECharts
v-if="trades"
ref="chart"
:option="cumProfitChartOptions"
:theme="settingsStore.chartTheme"
autoresize
/>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { EChartsOption } from 'echarts'; import { EChartsOption } from 'echarts';
import ECharts from 'vue-echarts'; import ECharts from 'vue-echarts';
@ -300,6 +290,16 @@ watch(
); );
</script> </script>
<template>
<ECharts
v-if="trades"
ref="chart"
:option="cumProfitChartOptions"
:theme="settingsStore.chartTheme"
autoresize
/>
</template>
<style scoped> <style scoped>
.echarts { .echarts {
width: 100%; width: 100%;

View File

@ -1,12 +1,3 @@
<template>
<ECharts
v-if="trades.length > 0"
:option="hourlyChartOptions"
autoresize
:theme="settingsStore.chartTheme"
/>
</template>
<script setup 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';
@ -154,6 +145,15 @@ const hourlyChartOptions = computed((): EChartsOption => {
}); });
</script> </script>
<template>
<ECharts
v-if="trades.length > 0"
:option="hourlyChartOptions"
autoresize
:theme="settingsStore.chartTheme"
/>
</template>
<style scoped> <style scoped>
.echarts { .echarts {
width: 100%; width: 100%;

View File

@ -1,3 +1,19 @@
<script setup lang="ts">
import { usePlotConfigStore } from '@/stores/plotConfig';
defineProps({
allowEdit: {
type: Boolean,
default: false,
},
editableName: {
type: String,
default: 'plot configuration',
},
});
const plotStore = usePlotConfigStore();
</script>
<template> <template>
<EditValue <EditValue
v-model="plotStore.plotConfigName" v-model="plotStore.plotConfigName"
@ -21,20 +37,4 @@
</EditValue> </EditValue>
</template> </template>
<script setup lang="ts">
import { usePlotConfigStore } from '@/stores/plotConfig';
defineProps({
allowEdit: {
type: Boolean,
default: false,
},
editableName: {
type: String,
default: 'plot configuration',
},
});
const plotStore = usePlotConfigStore();
</script>
<style scoped></style> <style scoped></style>

View File

@ -1,167 +1,3 @@
<template>
<div v-if="columns">
<BFormGroup label="Plot config name" label-for="idPlotConfigName">
<PlotConfigSelect allow-edit></PlotConfigSelect>
</BFormGroup>
<div class="col-mb-3">
<hr />
<BFormGroup label="Target Plot" label-for="FieldSel">
<EditValue
v-model="selSubPlot"
:allow-edit="!isMainPlot"
allow-add
editable-name="plot configuration"
align-vertical
@new="addSubplot"
@delete="deleteSubplot"
@rename="renameSubplot"
>
<BFormSelect id="FieldSel" v-model="selSubPlot" :options="subplots" :select-size="5">
</BFormSelect>
</EditValue>
</BFormGroup>
</div>
<hr />
<div>
<BFormGroup label="Indicators in this plot" label-for="selectedIndicators">
<BFormSelect
id="selectedIndicators"
v-model="selIndicatorName"
:disabled="addNewIndicator"
:options="usedColumns"
:select-size="4"
>
</BFormSelect>
</BFormGroup>
</div>
<div class="d-flex flex-row mt-1 gap-1">
<BButton
variant="secondary"
title="Remove indicator to plot"
size="sm"
:disabled="!selIndicatorName"
class="col"
@click="removeIndicator"
>
Remove indicator
</BButton>
<BButton
variant="secondary"
title="Load indicator config from template"
size="sm"
@click="fromPlotTemplateVisible = !fromPlotTemplateVisible"
>
Indicator from template
</BButton>
<BButton
variant="primary"
title="Add indicator to plot"
size="sm"
class="col"
:disabled="addNewIndicator"
@click="clickAddNewIndicator"
>
Add new indicator
</BButton>
</div>
<PlotIndicatorSelect
v-if="addNewIndicator"
:columns="columns"
class="mt-1"
label="Select indicator to add"
@indicator-selected="addNewIndicatorSelected"
/>
<PlotFromTemplate v-model:visible="fromPlotTemplateVisible" :columns="columns" />
<PlotIndicator
v-if="selIndicatorName && !fromPlotTemplateVisible"
v-model="selIndicator"
class="mt-1"
:columns="columns"
/>
<hr />
<div class="d-flex flex-row">
<BButton
class="ms-1 col"
variant="secondary"
size="sm"
:disabled="addNewIndicator"
title="Reset to last saved configuration"
@click="loadPlotConfig"
>Reset</BButton
>
<!--
Does Resetting a config to "nothing" make sense, or can this be done via "delete / create"?
<b-button
class="ms-1 col"
variant="secondary"
size="sm"
:disabled="addNewIndicator"
title="Start with empty configuration"
@click="clearConfig"
>Reset</b-button
> -->
<BButton
:disabled="
(botStore.activeBot.isWebserverMode && botStore.activeBot.botApiVersion < 2.23) ||
!botStore.activeBot.isBotOnline ||
addNewIndicator
"
class="ms-1 col"
variant="secondary"
size="sm"
@click="loadPlotConfigFromStrategy"
>
From strategy
</BButton>
<BButton
id="showButton"
class="ms-1 col"
variant="secondary"
size="sm"
:disabled="addNewIndicator"
title="Show configuration for easy transfer to a strategy"
@click="showConfig = !showConfig"
>{{ showConfig ? 'Hide' : 'Show' }}</BButton
>
<BButton
class="ms-1 col"
variant="primary"
size="sm"
data-toggle="tooltip"
:disabled="addNewIndicator"
title="Save configuration"
@click="savePlotConfig"
>Save</BButton
>
</div>
<BButton
v-if="showConfig"
class="ms-1 mt-1"
variant="secondary"
size="sm"
title="Load configuration from text box below"
@click="loadConfigFromString"
>Load from String</BButton
>
<div v-if="showConfig" class="col-mb-5 ms-1 mt-2">
<BFormTextarea
id="TextArea"
v-model="plotConfigJson"
class="textArea"
size="sm"
:state="tempPlotConfigValid"
>
</BFormTextarea>
</div>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { IndicatorConfig, PlotConfig } from '@/types'; import { IndicatorConfig, PlotConfig } from '@/types';
@ -386,6 +222,170 @@ watch(
const fromPlotTemplateVisible = ref(false); const fromPlotTemplateVisible = ref(false);
</script> </script>
<template>
<div v-if="columns">
<BFormGroup label="Plot config name" label-for="idPlotConfigName">
<PlotConfigSelect allow-edit></PlotConfigSelect>
</BFormGroup>
<div class="col-mb-3">
<hr />
<BFormGroup label="Target Plot" label-for="FieldSel">
<EditValue
v-model="selSubPlot"
:allow-edit="!isMainPlot"
allow-add
editable-name="plot configuration"
align-vertical
@new="addSubplot"
@delete="deleteSubplot"
@rename="renameSubplot"
>
<BFormSelect id="FieldSel" v-model="selSubPlot" :options="subplots" :select-size="5">
</BFormSelect>
</EditValue>
</BFormGroup>
</div>
<hr />
<div>
<BFormGroup label="Indicators in this plot" label-for="selectedIndicators">
<BFormSelect
id="selectedIndicators"
v-model="selIndicatorName"
:disabled="addNewIndicator"
:options="usedColumns"
:select-size="4"
>
</BFormSelect>
</BFormGroup>
</div>
<div class="d-flex flex-row mt-1 gap-1">
<BButton
variant="secondary"
title="Remove indicator to plot"
size="sm"
:disabled="!selIndicatorName"
class="col"
@click="removeIndicator"
>
Remove indicator
</BButton>
<BButton
variant="secondary"
title="Load indicator config from template"
size="sm"
@click="fromPlotTemplateVisible = !fromPlotTemplateVisible"
>
Indicator from template
</BButton>
<BButton
variant="primary"
title="Add indicator to plot"
size="sm"
class="col"
:disabled="addNewIndicator"
@click="clickAddNewIndicator"
>
Add new indicator
</BButton>
</div>
<PlotIndicatorSelect
v-if="addNewIndicator"
:columns="columns"
class="mt-1"
label="Select indicator to add"
@indicator-selected="addNewIndicatorSelected"
/>
<PlotFromTemplate v-model:visible="fromPlotTemplateVisible" :columns="columns" />
<PlotIndicator
v-if="selIndicatorName && !fromPlotTemplateVisible"
v-model="selIndicator"
class="mt-1"
:columns="columns"
/>
<hr />
<div class="d-flex flex-row">
<BButton
class="ms-1 col"
variant="secondary"
size="sm"
:disabled="addNewIndicator"
title="Reset to last saved configuration"
@click="loadPlotConfig"
>Reset</BButton
>
<!--
Does Resetting a config to "nothing" make sense, or can this be done via "delete / create"?
<b-button
class="ms-1 col"
variant="secondary"
size="sm"
:disabled="addNewIndicator"
title="Start with empty configuration"
@click="clearConfig"
>Reset</b-button
> -->
<BButton
:disabled="
(botStore.activeBot.isWebserverMode && botStore.activeBot.botApiVersion < 2.23) ||
!botStore.activeBot.isBotOnline ||
addNewIndicator
"
class="ms-1 col"
variant="secondary"
size="sm"
@click="loadPlotConfigFromStrategy"
>
From strategy
</BButton>
<BButton
id="showButton"
class="ms-1 col"
variant="secondary"
size="sm"
:disabled="addNewIndicator"
title="Show configuration for easy transfer to a strategy"
@click="showConfig = !showConfig"
>{{ showConfig ? 'Hide' : 'Show' }}</BButton
>
<BButton
class="ms-1 col"
variant="primary"
size="sm"
data-toggle="tooltip"
:disabled="addNewIndicator"
title="Save configuration"
@click="savePlotConfig"
>Save</BButton
>
</div>
<BButton
v-if="showConfig"
class="ms-1 mt-1"
variant="secondary"
size="sm"
title="Load configuration from text box below"
@click="loadConfigFromString"
>Load from String</BButton
>
<div v-if="showConfig" class="col-mb-5 ms-1 mt-2">
<BFormTextarea
id="TextArea"
v-model="plotConfigJson"
class="textArea"
size="sm"
:state="tempPlotConfigValid"
>
</BFormTextarea>
</div>
</div>
</template>
<style scoped lang="scss"> <style scoped lang="scss">
.textArea { .textArea {
min-height: 250px; min-height: 250px;

View File

@ -1,45 +1,3 @@
<template>
<div>
<div class="d-flex flex-col flex-xl-row justify-content-between mt-1">
<BFormGroup class="col flex-grow-1" label="Type" label-for="plotTypeSelector">
<BFormSelect
id="plotTypeSelector"
v-model="graphType"
size="sm"
:options="availableGraphTypes"
>
</BFormSelect>
</BFormGroup>
<BFormGroup label="Color" label-for="colsel" size="sm" class="ms-xl-1 col">
<BInputGroup>
<template #prepend>
<BFormInput
v-model="selColor"
type="color"
size="sm"
class="p-0"
style="max-width: 29px"
></BFormInput>
</template>
<BFormInput id="colsel" v-model="selColor" size="sm" class="flex-grow-1"> </BFormInput>
<template #append>
<BButton variant="primary" size="sm" @click="newColor">
<i-mdi-dice-multiple />
</BButton>
</template>
</BInputGroup>
</BFormGroup>
</div>
<PlotIndicatorSelect
v-if="graphType === ChartType.line"
v-model="fillTo"
:columns="columns"
class="mt-1"
label="Area chart - Fill to (leave empty for line chart)"
/>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { ChartType, IndicatorConfig } from '@/types'; import { ChartType, IndicatorConfig } from '@/types';
@ -111,4 +69,46 @@ watchDebounced(
); );
</script> </script>
<template>
<div>
<div class="d-flex flex-col flex-xl-row justify-content-between mt-1">
<BFormGroup class="col flex-grow-1" label="Type" label-for="plotTypeSelector">
<BFormSelect
id="plotTypeSelector"
v-model="graphType"
size="sm"
:options="availableGraphTypes"
>
</BFormSelect>
</BFormGroup>
<BFormGroup label="Color" label-for="colsel" size="sm" class="ms-xl-1 col">
<BInputGroup>
<template #prepend>
<BFormInput
v-model="selColor"
type="color"
size="sm"
class="p-0"
style="max-width: 29px"
></BFormInput>
</template>
<BFormInput id="colsel" v-model="selColor" size="sm" class="flex-grow-1"> </BFormInput>
<template #append>
<BButton variant="primary" size="sm" @click="newColor">
<i-mdi-dice-multiple />
</BButton>
</template>
</BInputGroup>
</BFormGroup>
</div>
<PlotIndicatorSelect
v-if="graphType === ChartType.line"
v-model="fillTo"
:columns="columns"
class="mt-1"
label="Area chart - Fill to (leave empty for line chart)"
/>
</div>
</template>
<style scoped></style> <style scoped></style>