mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-25 12:35:15 +00:00
chore: update block-order in components
script before template.
This commit is contained in:
parent
dc3553bb3e
commit
89181fdc71
|
@ -1,37 +1,3 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
<h3 class="me-auto d-inline">{{ hasWeekly ? 'Period' : 'Daily' }} Breakdown</h3>
|
||||
<BButton class="float-end" size="sm" @click="refreshSummary">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
<BFormRadioGroup
|
||||
v-if="hasWeekly"
|
||||
id="order-direction"
|
||||
v-model="periodicBreakdownPeriod"
|
||||
:options="periodicBreakdownSelections"
|
||||
name="radios-btn-default"
|
||||
size="sm"
|
||||
buttons
|
||||
style="min-width: 10em"
|
||||
button-variant="outline-primary"
|
||||
@change="refreshSummary"
|
||||
></BFormRadioGroup>
|
||||
|
||||
<div class="ps-1">
|
||||
<TimePeriodChart
|
||||
v-if="selectedStats"
|
||||
:daily-stats="selectedStatsSorted"
|
||||
:show-title="false"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<BTable class="table-sm" :items="selectedStats.data" :fields="dailyFields"> </BTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { TableField } from 'bootstrap-vue-next';
|
||||
|
@ -105,3 +71,37 @@ onMounted(() => {
|
|||
refreshSummary();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
<h3 class="me-auto d-inline">{{ hasWeekly ? 'Period' : 'Daily' }} Breakdown</h3>
|
||||
<BButton class="float-end" size="sm" @click="refreshSummary">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
<BFormRadioGroup
|
||||
v-if="hasWeekly"
|
||||
id="order-direction"
|
||||
v-model="periodicBreakdownPeriod"
|
||||
:options="periodicBreakdownSelections"
|
||||
name="radios-btn-default"
|
||||
size="sm"
|
||||
buttons
|
||||
style="min-width: 10em"
|
||||
button-variant="outline-primary"
|
||||
@change="refreshSummary"
|
||||
></BFormRadioGroup>
|
||||
|
||||
<div class="ps-1">
|
||||
<TimePeriodChart
|
||||
v-if="selectedStats"
|
||||
:daily-stats="selectedStatsSorted"
|
||||
:show-title="false"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<BTable class="table-sm" :items="selectedStats.data" :fields="dailyFields"> </BTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const autoRefreshLoc = computed({
|
||||
get() {
|
||||
return botStore.globalAutoRefresh;
|
||||
},
|
||||
set(newValue: boolean) {
|
||||
botStore.setGlobalAutoRefresh(newValue);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex align-items-center ms-2">
|
||||
<BFormCheckbox
|
||||
|
@ -17,18 +31,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const autoRefreshLoc = computed({
|
||||
get() {
|
||||
return botStore.globalAutoRefresh;
|
||||
},
|
||||
set(newValue: boolean) {
|
||||
botStore.setGlobalAutoRefresh(newValue);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,27 +1,3 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="w-100 d-flex">
|
||||
<BFormSelect
|
||||
id="strategy-select"
|
||||
v-model="locStrategy"
|
||||
:options="botStore.activeBot.strategyList"
|
||||
>
|
||||
</BFormSelect>
|
||||
<div class="ms-1">
|
||||
<BButton @click="botStore.activeBot.getStrategyList">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
v-if="showDetails && botStore.activeBot.strategy"
|
||||
v-model="strategyCode"
|
||||
class="w-100 h-100"
|
||||
></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
|
@ -50,3 +26,27 @@ onMounted(() => {
|
|||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="w-100 d-flex">
|
||||
<BFormSelect
|
||||
id="strategy-select"
|
||||
v-model="locStrategy"
|
||||
:options="botStore.activeBot.strategyList"
|
||||
>
|
||||
</BFormSelect>
|
||||
<div class="ms-1">
|
||||
<BButton @click="botStore.activeBot.getStrategyList">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
v-if="showDetails && botStore.activeBot.strategy"
|
||||
v-model="strategyCode"
|
||||
class="w-100 h-100"
|
||||
></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,43 +1,3 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-center">
|
||||
<div>
|
||||
<label for="dateFrom">Start Date</label>
|
||||
<Datepicker
|
||||
id="dateFrom"
|
||||
v-model="dateFrom"
|
||||
:dark="settingsStore.isDarkTheme"
|
||||
:max-date="now"
|
||||
model-type="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
class="mt-1"
|
||||
text-input
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
></Datepicker>
|
||||
</div>
|
||||
<div class="ms-2">
|
||||
<label for="dateTo">End Date</label>
|
||||
<Datepicker
|
||||
v-model="dateTo"
|
||||
:dark="settingsStore.isDarkTheme"
|
||||
class="mt-1"
|
||||
:max-date="tomorrow"
|
||||
model-type="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
text-input
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
></Datepicker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="mt-1 text-start">
|
||||
Timerange: <b>{{ timeRange }}</b>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Datepicker from '@vuepic/vue-datepicker';
|
||||
import '@vuepic/vue-datepicker/dist/main.css';
|
||||
|
@ -103,4 +63,44 @@ onMounted(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-center">
|
||||
<div>
|
||||
<label for="dateFrom">Start Date</label>
|
||||
<Datepicker
|
||||
id="dateFrom"
|
||||
v-model="dateFrom"
|
||||
:dark="settingsStore.isDarkTheme"
|
||||
:max-date="now"
|
||||
model-type="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
class="mt-1"
|
||||
text-input
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
></Datepicker>
|
||||
</div>
|
||||
<div class="ms-2">
|
||||
<label for="dateTo">End Date</label>
|
||||
<Datepicker
|
||||
v-model="dateTo"
|
||||
:dark="settingsStore.isDarkTheme"
|
||||
class="mt-1"
|
||||
:max-date="tomorrow"
|
||||
model-type="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
text-input
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
></Datepicker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="mt-1 text-start">
|
||||
Timerange: <b>{{ timeRange }}</b>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
<template>
|
||||
<BFormSelect
|
||||
v-model="selectedTimeframe"
|
||||
placeholder="Use strategy default"
|
||||
:options="availableTimeframes"
|
||||
@change="emitSelectedTimeframe"
|
||||
></BFormSelect>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
value: { default: '', type: String },
|
||||
|
@ -52,4 +43,13 @@ const emitSelectedTimeframe = () => {
|
|||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BFormSelect
|
||||
v-model="selectedTimeframe"
|
||||
placeholder="Use strategy default"
|
||||
:options="availableTimeframes"
|
||||
@change="emitSelectedTimeframe"
|
||||
></BFormSelect>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
defineProps({
|
||||
botApiVersion: {
|
||||
type: Number,
|
||||
default: 1.0,
|
||||
},
|
||||
trade: {
|
||||
type: Object as () => Trade,
|
||||
required: true,
|
||||
},
|
||||
enableForceEntry: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
defineEmits<{
|
||||
forceExit: [trade: Trade, type?: 'limit' | 'market'];
|
||||
forceExitPartial: [trade: Trade];
|
||||
cancelOpenOrder: [trade: Trade];
|
||||
reloadTrade: [trade: Trade];
|
||||
deleteTrade: [trade: Trade];
|
||||
forceEntry: [trade: Trade];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-column">
|
||||
<BButton
|
||||
|
@ -75,31 +102,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
defineProps({
|
||||
botApiVersion: {
|
||||
type: Number,
|
||||
default: 1.0,
|
||||
},
|
||||
trade: {
|
||||
type: Object as () => Trade,
|
||||
required: true,
|
||||
},
|
||||
enableForceEntry: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
defineEmits<{
|
||||
forceExit: [trade: Trade, type?: 'limit' | 'market'];
|
||||
forceExitPartial: [trade: Trade];
|
||||
cancelOpenOrder: [trade: Trade];
|
||||
reloadTrade: [trade: Trade];
|
||||
deleteTrade: [trade: Trade];
|
||||
forceEntry: [trade: Trade];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
const colorStore = useColorStore();
|
||||
|
||||
defineProps({
|
||||
trade: { required: true, type: Object as () => Trade },
|
||||
stakeCurrency: { required: true, type: String },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container text-start">
|
||||
<div class="row">
|
||||
|
@ -139,17 +150,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
const colorStore = useColorStore();
|
||||
|
||||
defineProps({
|
||||
trade: { required: true, type: Object as () => Trade },
|
||||
stakeCurrency: { required: true, type: String },
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.detail-header {
|
||||
border-bottom: 1px solid;
|
||||
|
|
|
@ -1,102 +1,3 @@
|
|||
<template>
|
||||
<div class="h-100 overflow-auto w-100">
|
||||
<BTable
|
||||
ref="tradesTable"
|
||||
small
|
||||
hover
|
||||
stacked="md"
|
||||
:items="
|
||||
trades.filter(
|
||||
(t) =>
|
||||
t.pair.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
t.exit_reason?.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
t.enter_tag?.toLowerCase().includes(filterText.toLowerCase()),
|
||||
) as unknown as TableItem[]
|
||||
"
|
||||
:fields="tableFields"
|
||||
show-empty
|
||||
:empty-text="emptyText"
|
||||
:per-page="perPage"
|
||||
:current-page="currentPage"
|
||||
primary-key="botTradeId"
|
||||
selectable
|
||||
:select-head="false"
|
||||
select-mode="single"
|
||||
@row-contextmenu="handleContextMenuEvent"
|
||||
@row-clicked="onRowClicked"
|
||||
@row-selected="onRowSelected"
|
||||
>
|
||||
<template #cell(actions)="{ index, item }">
|
||||
<TradeActionsPopover
|
||||
:id="index"
|
||||
:enable-force-entry="botStore.activeBot.botState.force_entry_enable"
|
||||
:trade="item as unknown as Trade"
|
||||
:bot-api-version="botStore.activeBot.botApiVersion"
|
||||
@delete-trade="removeTradeHandler(item as unknown as Trade)"
|
||||
@force-exit="forceExitHandler"
|
||||
@force-exit-partial="forceExitPartialHandler"
|
||||
@cancel-open-order="cancelOpenOrderHandler"
|
||||
@reload-trade="reloadTradeHandler"
|
||||
@force-entry="handleForceEntry"
|
||||
/>
|
||||
</template>
|
||||
<template #cell(pair)="row">
|
||||
<span>
|
||||
{{ `${row.item.pair}${row.item.open_order_id || row.item.has_open_orders ? '*' : ''}` }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(trade_id)="row">
|
||||
{{ row.item.trade_id }}
|
||||
{{
|
||||
botStore.activeBot.botApiVersion > 2.0 && row.item.trading_mode !== 'spot'
|
||||
? '| ' + (row.item.is_short ? 'Short' : 'Long')
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #cell(stake_amount)="row">
|
||||
{{ formatPriceWithDecimals(row.item.stake_amount) }}
|
||||
{{ row.item.trading_mode !== 'spot' ? `(${row.item.leverage}x)` : '' }}
|
||||
</template>
|
||||
<template #cell(profit)="row">
|
||||
<TradeProfit :trade="row.item as unknown as Trade" />
|
||||
</template>
|
||||
<template #cell(open_timestamp)="row">
|
||||
<DateTimeTZ :date="(row.item as unknown as Trade).open_timestamp" />
|
||||
</template>
|
||||
<template #cell(close_timestamp)="row">
|
||||
<DateTimeTZ :date="(row.item as unknown as Trade).close_timestamp ?? 0" />
|
||||
</template>
|
||||
</BTable>
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<BPagination
|
||||
v-if="!activeTrades"
|
||||
v-model="currentPage"
|
||||
:total-rows="rows"
|
||||
:per-page="perPage"
|
||||
aria-controls="my-table"
|
||||
></BPagination>
|
||||
<BFormGroup v-if="showFilter" label-for="trade-filter">
|
||||
<BFormInput id="trade-filter" v-model="filterText" type="text" placeholder="Filter" />
|
||||
</BFormGroup>
|
||||
</div>
|
||||
<ForceExitForm
|
||||
v-if="activeTrades"
|
||||
v-model="forceExitVisible"
|
||||
:trade="feTrade"
|
||||
:quote-currency-decimals="botStore.activeBot.botState.stake_currency_decimals"
|
||||
/>
|
||||
<ForceEntryForm
|
||||
v-model="increasePosition.visible"
|
||||
:pair="increasePosition.trade?.pair"
|
||||
position-increase
|
||||
/>
|
||||
|
||||
<BModal v-model="removeTradeVisible" title="Exit trade" @ok="forceExitExecuter">
|
||||
{{ confirmExitText }}
|
||||
</BModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { MultiDeletePayload, MultiForcesellPayload, Trade } from '@/types';
|
||||
|
||||
|
@ -315,6 +216,105 @@ watch(
|
|||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-100 overflow-auto w-100">
|
||||
<BTable
|
||||
ref="tradesTable"
|
||||
small
|
||||
hover
|
||||
stacked="md"
|
||||
:items="
|
||||
trades.filter(
|
||||
(t) =>
|
||||
t.pair.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
t.exit_reason?.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
t.enter_tag?.toLowerCase().includes(filterText.toLowerCase()),
|
||||
) as unknown as TableItem[]
|
||||
"
|
||||
:fields="tableFields"
|
||||
show-empty
|
||||
:empty-text="emptyText"
|
||||
:per-page="perPage"
|
||||
:current-page="currentPage"
|
||||
primary-key="botTradeId"
|
||||
selectable
|
||||
:select-head="false"
|
||||
select-mode="single"
|
||||
@row-contextmenu="handleContextMenuEvent"
|
||||
@row-clicked="onRowClicked"
|
||||
@row-selected="onRowSelected"
|
||||
>
|
||||
<template #cell(actions)="{ index, item }">
|
||||
<TradeActionsPopover
|
||||
:id="index"
|
||||
:enable-force-entry="botStore.activeBot.botState.force_entry_enable"
|
||||
:trade="item as unknown as Trade"
|
||||
:bot-api-version="botStore.activeBot.botApiVersion"
|
||||
@delete-trade="removeTradeHandler(item as unknown as Trade)"
|
||||
@force-exit="forceExitHandler"
|
||||
@force-exit-partial="forceExitPartialHandler"
|
||||
@cancel-open-order="cancelOpenOrderHandler"
|
||||
@reload-trade="reloadTradeHandler"
|
||||
@force-entry="handleForceEntry"
|
||||
/>
|
||||
</template>
|
||||
<template #cell(pair)="row">
|
||||
<span>
|
||||
{{ `${row.item.pair}${row.item.open_order_id || row.item.has_open_orders ? '*' : ''}` }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(trade_id)="row">
|
||||
{{ row.item.trade_id }}
|
||||
{{
|
||||
botStore.activeBot.botApiVersion > 2.0 && row.item.trading_mode !== 'spot'
|
||||
? '| ' + (row.item.is_short ? 'Short' : 'Long')
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #cell(stake_amount)="row">
|
||||
{{ formatPriceWithDecimals(row.item.stake_amount) }}
|
||||
{{ row.item.trading_mode !== 'spot' ? `(${row.item.leverage}x)` : '' }}
|
||||
</template>
|
||||
<template #cell(profit)="row">
|
||||
<TradeProfit :trade="row.item as unknown as Trade" />
|
||||
</template>
|
||||
<template #cell(open_timestamp)="row">
|
||||
<DateTimeTZ :date="(row.item as unknown as Trade).open_timestamp" />
|
||||
</template>
|
||||
<template #cell(close_timestamp)="row">
|
||||
<DateTimeTZ :date="(row.item as unknown as Trade).close_timestamp ?? 0" />
|
||||
</template>
|
||||
</BTable>
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<BPagination
|
||||
v-if="!activeTrades"
|
||||
v-model="currentPage"
|
||||
:total-rows="rows"
|
||||
:per-page="perPage"
|
||||
aria-controls="my-table"
|
||||
></BPagination>
|
||||
<BFormGroup v-if="showFilter" label-for="trade-filter">
|
||||
<BFormInput id="trade-filter" v-model="filterText" type="text" placeholder="Filter" />
|
||||
</BFormGroup>
|
||||
</div>
|
||||
<ForceExitForm
|
||||
v-if="activeTrades"
|
||||
v-model="forceExitVisible"
|
||||
:trade="feTrade"
|
||||
:quote-currency-decimals="botStore.activeBot.botState.stake_currency_decimals"
|
||||
/>
|
||||
<ForceEntryForm
|
||||
v-model="increasePosition.visible"
|
||||
:pair="increasePosition.trade?.pair"
|
||||
position-increase
|
||||
/>
|
||||
|
||||
<BModal v-model="removeTradeVisible" title="Exit trade" @ok="forceExitExecuter">
|
||||
{{ confirmExitText }}
|
||||
</BModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-body {
|
||||
padding: 0 0.2em;
|
||||
|
|
|
@ -1,3 +1,43 @@
|
|||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const props = defineProps({
|
||||
trades: { required: true, type: Array as () => Trade[] },
|
||||
backtestMode: { required: false, default: false, type: Boolean },
|
||||
});
|
||||
const emit = defineEmits<{ 'trade-select': [trade: Trade] }>();
|
||||
|
||||
const botStore = useBotStore();
|
||||
const selectedTrade = ref({} as Trade);
|
||||
const sortNewestFirst = ref(true);
|
||||
|
||||
const onTradeSelect = (trade: Trade) => {
|
||||
selectedTrade.value = trade;
|
||||
emit('trade-select', trade);
|
||||
};
|
||||
|
||||
const sortedTrades = computed(() => {
|
||||
return props.trades
|
||||
.slice()
|
||||
.sort((a, b) =>
|
||||
sortNewestFirst.value
|
||||
? b.open_timestamp - a.open_timestamp
|
||||
: a.open_timestamp - b.open_timestamp,
|
||||
);
|
||||
});
|
||||
|
||||
const ordersVisible = ref(sortedTrades.value.map(() => false));
|
||||
|
||||
watch(
|
||||
() => botStore.activeBot.selectedPair,
|
||||
() => {
|
||||
ordersVisible.value = sortedTrades.value.map(() => false);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<BListGroup>
|
||||
|
@ -57,46 +97,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const props = defineProps({
|
||||
trades: { required: true, type: Array as () => Trade[] },
|
||||
backtestMode: { required: false, default: false, type: Boolean },
|
||||
});
|
||||
const emit = defineEmits<{ 'trade-select': [trade: Trade] }>();
|
||||
|
||||
const botStore = useBotStore();
|
||||
const selectedTrade = ref({} as Trade);
|
||||
const sortNewestFirst = ref(true);
|
||||
|
||||
const onTradeSelect = (trade: Trade) => {
|
||||
selectedTrade.value = trade;
|
||||
emit('trade-select', trade);
|
||||
};
|
||||
|
||||
const sortedTrades = computed(() => {
|
||||
return props.trades
|
||||
.slice()
|
||||
.sort((a, b) =>
|
||||
sortNewestFirst.value
|
||||
? b.open_timestamp - a.open_timestamp
|
||||
: a.open_timestamp - b.open_timestamp,
|
||||
);
|
||||
});
|
||||
|
||||
const ordersVisible = ref(sortedTrades.value.map(() => false));
|
||||
|
||||
watch(
|
||||
() => botStore.activeBot.selectedPair,
|
||||
() => {
|
||||
ordersVisible.value = sortedTrades.value.map(() => false);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.list-group {
|
||||
text-align: left;
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
<template>
|
||||
<ProfitPill
|
||||
:profit-ratio="profitRatio"
|
||||
:profit-abs="profitAbs"
|
||||
:profit-desc="profitDesc"
|
||||
:stake-currency="trade.quote_currency || 'USDT'"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
|
@ -60,4 +51,13 @@ const profitDesc = computed((): string => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProfitPill
|
||||
:profit-ratio="profitRatio"
|
||||
:profit-abs="profitAbs"
|
||||
:profit-desc="profitDesc"
|
||||
:stake-currency="trade.quote_currency || 'USDT'"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
|
||||
defineProps({
|
||||
content: { type: [String, Array<string>], required: true },
|
||||
isValid: { type: Boolean, default: true },
|
||||
});
|
||||
|
||||
const { copy, isSupported } = useClipboard();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="copy-container position-relative">
|
||||
<i-mdi-content-copy
|
||||
|
@ -10,17 +21,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
|
||||
defineProps({
|
||||
content: { type: [String, Array<string>], required: true },
|
||||
isValid: { type: Boolean, default: true },
|
||||
});
|
||||
|
||||
const { copy, isSupported } = useClipboard();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.copy-container {
|
||||
.copy-button {
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
<template>
|
||||
<span :title="timezoneTooltip">{{ formattedDate }}</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
date: { required: true, type: Number },
|
||||
|
@ -29,4 +25,8 @@ const timezoneTooltip = computed((): string => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span :title="timezoneTooltip">{{ formattedDate }}</span>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,65 +1,3 @@
|
|||
<template>
|
||||
<form class="d-flex flex-row" @submit.prevent="saveNewName">
|
||||
<div class="flex-grow-1">
|
||||
<slot v-if="mode === EditState.None"> </slot>
|
||||
<BFormInput v-else v-model="localName" size="sm"> </BFormInput>
|
||||
</div>
|
||||
<div
|
||||
class="flex-grow-2 mt-auto d-flex gap-1 ms-1"
|
||||
:class="alignVertical ? 'flex-column' : 'flex-row'"
|
||||
>
|
||||
<template v-if="allowEdit && mode === EditState.None">
|
||||
<BButton
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Edit this ${editableName}.`"
|
||||
@click="mode = EditState.Editing"
|
||||
>
|
||||
<i-mdi-pencil />
|
||||
</BButton>
|
||||
<BButton
|
||||
v-if="allowDuplicate"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Duplicate ${editableName}.`"
|
||||
@click="duplicate"
|
||||
>
|
||||
<i-mdi-content-copy />
|
||||
</BButton>
|
||||
<BButton
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Delete this ${editableName}.`"
|
||||
@click="$emit('delete', modelValue)"
|
||||
>
|
||||
<i-mdi-delete />
|
||||
</BButton>
|
||||
</template>
|
||||
<BButton
|
||||
v-if="allowAdd && mode === EditState.None"
|
||||
size="sm"
|
||||
:title="`Add new ${editableName}.`"
|
||||
variant="primary"
|
||||
@click="addNewClick"
|
||||
><i-mdi-plus-box-outline />
|
||||
</BButton>
|
||||
<template v-if="mode !== EditState.None">
|
||||
<BButton
|
||||
size="sm"
|
||||
:title="`Add new ${editableName}`"
|
||||
variant="primary"
|
||||
@click="saveNewName"
|
||||
>
|
||||
<i-mdi-check />
|
||||
</BButton>
|
||||
<BButton size="sm" title="Abort" variant="secondary" @click="abort">
|
||||
<i-mdi-close />
|
||||
</BButton>
|
||||
</template>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
@ -142,3 +80,65 @@ function saveNewName() {
|
|||
mode.value = EditState.None;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form class="d-flex flex-row" @submit.prevent="saveNewName">
|
||||
<div class="flex-grow-1">
|
||||
<slot v-if="mode === EditState.None"> </slot>
|
||||
<BFormInput v-else v-model="localName" size="sm"> </BFormInput>
|
||||
</div>
|
||||
<div
|
||||
class="flex-grow-2 mt-auto d-flex gap-1 ms-1"
|
||||
:class="alignVertical ? 'flex-column' : 'flex-row'"
|
||||
>
|
||||
<template v-if="allowEdit && mode === EditState.None">
|
||||
<BButton
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Edit this ${editableName}.`"
|
||||
@click="mode = EditState.Editing"
|
||||
>
|
||||
<i-mdi-pencil />
|
||||
</BButton>
|
||||
<BButton
|
||||
v-if="allowDuplicate"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Duplicate ${editableName}.`"
|
||||
@click="duplicate"
|
||||
>
|
||||
<i-mdi-content-copy />
|
||||
</BButton>
|
||||
<BButton
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Delete this ${editableName}.`"
|
||||
@click="$emit('delete', modelValue)"
|
||||
>
|
||||
<i-mdi-delete />
|
||||
</BButton>
|
||||
</template>
|
||||
<BButton
|
||||
v-if="allowAdd && mode === EditState.None"
|
||||
size="sm"
|
||||
:title="`Add new ${editableName}.`"
|
||||
variant="primary"
|
||||
@click="addNewClick"
|
||||
><i-mdi-plus-box-outline />
|
||||
</BButton>
|
||||
<template v-if="mode !== EditState.None">
|
||||
<BButton
|
||||
size="sm"
|
||||
:title="`Add new ${editableName}`"
|
||||
variant="primary"
|
||||
@click="saveNewName"
|
||||
>
|
||||
<i-mdi-check />
|
||||
</BButton>
|
||||
<BButton size="sm" title="Abort" variant="secondary" @click="abort">
|
||||
<i-mdi-close />
|
||||
</BButton>
|
||||
</template>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<div :title="hint">
|
||||
<i-mdi-information-outline />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
hint: { type: String, required: true },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :title="hint">
|
||||
<i-mdi-information-outline />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -1,18 +1,3 @@
|
|||
<template>
|
||||
<BModal
|
||||
id="MsgBoxModal"
|
||||
ref="removeTradeModal"
|
||||
v-model="showRef"
|
||||
:title="title"
|
||||
@ok="msgBoxOK"
|
||||
@cancel="showRef = false"
|
||||
@keyup.esc="showRef = false"
|
||||
@keyup.enter="msgBoxOK"
|
||||
>
|
||||
{{ message }}
|
||||
</BModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
export interface MsgBoxObject {
|
||||
title: string;
|
||||
|
@ -41,4 +26,19 @@ const show = (msg: MsgBoxObject) => {
|
|||
defineExpose({ show });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BModal
|
||||
id="MsgBoxModal"
|
||||
ref="removeTradeModal"
|
||||
v-model="showRef"
|
||||
:title="title"
|
||||
@ok="msgBoxOK"
|
||||
@cancel="showRef = false"
|
||||
@keyup.esc="showRef = false"
|
||||
@keyup.enter="msgBoxOK"
|
||||
>
|
||||
{{ message }}
|
||||
</BModal>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,24 +1,3 @@
|
|||
<template>
|
||||
<div
|
||||
class="d-flex justify-content-between align-items-center profit-pill ps-2 pe-1"
|
||||
:class="isProfitable ? 'profit-pill-profit' : ''"
|
||||
:title="profitDesc"
|
||||
>
|
||||
<ProfitSymbol :profit="(profitRatio || profitAbs) ?? 0" />
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center flex-grow-1">
|
||||
{{ profitRatio !== undefined ? formatPercent(profitRatio, 2) : '' }}
|
||||
<span
|
||||
v-if="profitString"
|
||||
class="ms-1"
|
||||
:class="profitRatio ? 'small' : ''"
|
||||
:title="stakeCurrency"
|
||||
>{{ profitString }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
profitRatio: { required: false, default: undefined, type: Number },
|
||||
|
@ -47,6 +26,27 @@ const profitString = computed((): string => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="d-flex justify-content-between align-items-center profit-pill ps-2 pe-1"
|
||||
:class="isProfitable ? 'profit-pill-profit' : ''"
|
||||
:title="profitDesc"
|
||||
>
|
||||
<ProfitSymbol :profit="(profitRatio || profitAbs) ?? 0" />
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center flex-grow-1">
|
||||
{{ profitRatio !== undefined ? formatPercent(profitRatio, 2) : '' }}
|
||||
<span
|
||||
v-if="profitString"
|
||||
class="ms-1"
|
||||
:class="profitRatio ? 'small' : ''"
|
||||
:title="stakeCurrency"
|
||||
>{{ profitString }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.profit-pill {
|
||||
border: 2px solid $color-loss;
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
<template>
|
||||
<div class="d-inline-block">
|
||||
<div :class="isProfitable ? 'triangle-up' : 'triangle-down'"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
profit: { type: Number, required: true },
|
||||
|
@ -13,6 +7,12 @@ const isProfitable = computed(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-inline-block">
|
||||
<div :class="isProfitable ? 'triangle-up' : 'triangle-down'"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.triangle-up {
|
||||
width: 0;
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
defineProps({
|
||||
description: { type: String, required: true },
|
||||
help: { type: String, default: '', required: false },
|
||||
classLabel: { type: String, default: 'col-4 fw-bold mb-0' },
|
||||
classValue: { type: String, default: 'col-8' },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex">
|
||||
<div class="d-flex justify-content-between me-2" :class="classLabel">
|
||||
|
@ -9,14 +18,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
description: { type: String, required: true },
|
||||
help: { type: String, default: '', required: false },
|
||||
classLabel: { type: String, default: 'col-4 fw-bold mb-0' },
|
||||
classValue: { type: String, default: 'col-8' },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
defineProps({
|
||||
header: { required: false, type: String, default: '' },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card h-100 w-100">
|
||||
<div class="drag-header card-header">
|
||||
|
@ -11,12 +17,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
header: { required: false, type: String, default: '' },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card-header {
|
||||
padding: 0.25rem 0.5rem;
|
||||
|
|
|
@ -1,3 +1,101 @@
|
|||
<script setup lang="ts">
|
||||
import Favico from 'favico.js';
|
||||
|
||||
import { OpenTradeVizOptions, useSettingsStore } from '@/stores/settings';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const botStore = useBotStore();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const favicon = ref<Favico | undefined>(undefined);
|
||||
const pingInterval = ref<number>();
|
||||
|
||||
async function clickLogout() {
|
||||
botStore.removeBot(botStore.selectedBot);
|
||||
// TODO: This should be per bot
|
||||
await router.push('/');
|
||||
}
|
||||
|
||||
const setOpenTradesAsPill = (tradeCount: number) => {
|
||||
if (!favicon.value) {
|
||||
favicon.value = new Favico({
|
||||
animation: 'none',
|
||||
// position: 'up',
|
||||
// fontStyle: 'normal',
|
||||
// bgColor: '#',
|
||||
// textColor: '#FFFFFF',
|
||||
});
|
||||
}
|
||||
if (tradeCount !== 0 && settingsStore.openTradesInTitle === 'showPill') {
|
||||
favicon.value.badge(tradeCount);
|
||||
} else {
|
||||
favicon.value.reset();
|
||||
console.log('reset');
|
||||
}
|
||||
};
|
||||
const resetDynamicLayout = (): void => {
|
||||
console.log(`resetLayout called for ${route?.fullPath}`);
|
||||
switch (route?.fullPath) {
|
||||
case '/trade':
|
||||
layoutStore.resetTradingLayout();
|
||||
break;
|
||||
case '/dashboard':
|
||||
layoutStore.resetDashboardLayout();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
};
|
||||
const setTitle = () => {
|
||||
let title = 'freqUI';
|
||||
if (settingsStore.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
title = `(${botStore.activeBotorUndefined?.openTradeCount}) ${title}`;
|
||||
}
|
||||
if (botStore.activeBotorUndefined?.botName) {
|
||||
title = `${title} - ${botStore.activeBotorUndefined?.botName}`;
|
||||
}
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (pingInterval.value) {
|
||||
clearInterval(pingInterval.value);
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await settingsStore.loadUIVersion();
|
||||
pingInterval.value = window.setInterval(botStore.pingAll, 60000);
|
||||
});
|
||||
|
||||
settingsStore.$subscribe((_, state) => {
|
||||
const needsUpdate = settingsStore.openTradesInTitle !== state.openTradesInTitle;
|
||||
if (needsUpdate) {
|
||||
setTitle();
|
||||
setOpenTradesAsPill(botStore.activeBotorUndefined?.openTradeCount || 0);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => botStore.activeBotorUndefined?.botName,
|
||||
() => setTitle(),
|
||||
);
|
||||
watch(
|
||||
() => botStore.activeBotorUndefined?.openTradeCount,
|
||||
() => {
|
||||
if (settingsStore.openTradesInTitle === OpenTradeVizOptions.showPill) {
|
||||
setOpenTradesAsPill(botStore.activeBotorUndefined?.openTradeCount ?? 0);
|
||||
} else if (settingsStore.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
setTitle();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<BNavbar toggleable="sm" dark variant="primary">
|
||||
|
@ -129,104 +227,6 @@
|
|||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Favico from 'favico.js';
|
||||
|
||||
import { OpenTradeVizOptions, useSettingsStore } from '@/stores/settings';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const botStore = useBotStore();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const favicon = ref<Favico | undefined>(undefined);
|
||||
const pingInterval = ref<number>();
|
||||
|
||||
async function clickLogout() {
|
||||
botStore.removeBot(botStore.selectedBot);
|
||||
// TODO: This should be per bot
|
||||
await router.push('/');
|
||||
}
|
||||
|
||||
const setOpenTradesAsPill = (tradeCount: number) => {
|
||||
if (!favicon.value) {
|
||||
favicon.value = new Favico({
|
||||
animation: 'none',
|
||||
// position: 'up',
|
||||
// fontStyle: 'normal',
|
||||
// bgColor: '#',
|
||||
// textColor: '#FFFFFF',
|
||||
});
|
||||
}
|
||||
if (tradeCount !== 0 && settingsStore.openTradesInTitle === 'showPill') {
|
||||
favicon.value.badge(tradeCount);
|
||||
} else {
|
||||
favicon.value.reset();
|
||||
console.log('reset');
|
||||
}
|
||||
};
|
||||
const resetDynamicLayout = (): void => {
|
||||
console.log(`resetLayout called for ${route?.fullPath}`);
|
||||
switch (route?.fullPath) {
|
||||
case '/trade':
|
||||
layoutStore.resetTradingLayout();
|
||||
break;
|
||||
case '/dashboard':
|
||||
layoutStore.resetDashboardLayout();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
};
|
||||
const setTitle = () => {
|
||||
let title = 'freqUI';
|
||||
if (settingsStore.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
title = `(${botStore.activeBotorUndefined?.openTradeCount}) ${title}`;
|
||||
}
|
||||
if (botStore.activeBotorUndefined?.botName) {
|
||||
title = `${title} - ${botStore.activeBotorUndefined?.botName}`;
|
||||
}
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (pingInterval.value) {
|
||||
clearInterval(pingInterval.value);
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await settingsStore.loadUIVersion();
|
||||
pingInterval.value = window.setInterval(botStore.pingAll, 60000);
|
||||
});
|
||||
|
||||
settingsStore.$subscribe((_, state) => {
|
||||
const needsUpdate = settingsStore.openTradesInTitle !== state.openTradesInTitle;
|
||||
if (needsUpdate) {
|
||||
setTitle();
|
||||
setOpenTradesAsPill(botStore.activeBotorUndefined?.openTradeCount || 0);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => botStore.activeBotorUndefined?.botName,
|
||||
() => setTitle(),
|
||||
);
|
||||
watch(
|
||||
() => botStore.activeBotorUndefined?.openTradeCount,
|
||||
() => {
|
||||
if (settingsStore.openTradesInTitle === OpenTradeVizOptions.showPill) {
|
||||
setOpenTradesAsPill(botStore.activeBotorUndefined?.openTradeCount ?? 0);
|
||||
} else if (settingsStore.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
setTitle();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.logo {
|
||||
vertical-align: middle;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="d-md-none">
|
||||
<!-- Only visible on xs (phone) viewport! -->
|
||||
|
@ -47,12 +53,6 @@
|
|||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
[data-theme='dark'] {
|
||||
.router-link-active,
|
||||
|
|
|
@ -1,3 +1,75 @@
|
|||
<script setup lang="ts">
|
||||
import { useBtStore } from '@/stores/btStore';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
enum BtRunModes {
|
||||
run = 'run',
|
||||
results = 'results',
|
||||
visualize = 'visualize',
|
||||
visualizesummary = 'visualize-summary',
|
||||
compareresults = 'compare-results',
|
||||
historicresults = 'historicResults',
|
||||
}
|
||||
|
||||
const botStore = useBotStore();
|
||||
const btStore = useBtStore();
|
||||
|
||||
const hasBacktestResult = computed(() =>
|
||||
botStore.activeBot.backtestHistory
|
||||
? Object.keys(botStore.activeBot.backtestHistory).length !== 0
|
||||
: false,
|
||||
);
|
||||
const hasMultiBacktestResult = computed(() =>
|
||||
botStore.activeBot.backtestHistory
|
||||
? Object.keys(botStore.activeBot.backtestHistory).length > 1
|
||||
: false,
|
||||
);
|
||||
|
||||
const timeframe = computed((): string => {
|
||||
try {
|
||||
return botStore.activeBot.selectedBacktestResult.timeframe;
|
||||
} catch (err) {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
const showLeftBar = ref(false);
|
||||
|
||||
const btFormMode = ref<BtRunModes>(BtRunModes.run);
|
||||
const pollInterval = ref<number | null>(null);
|
||||
|
||||
const selectBacktestResult = () => {
|
||||
// Set parameters for this result
|
||||
btStore.strategy = botStore.activeBot.selectedBacktestResult.strategy_name;
|
||||
botStore.activeBot.getStrategy(btStore.strategy);
|
||||
btStore.selectedTimeframe = botStore.activeBot.selectedBacktestResult.timeframe;
|
||||
btStore.selectedDetailTimeframe =
|
||||
botStore.activeBot.selectedBacktestResult.timeframe_detail || '';
|
||||
// TODO: maybe this should not use timerange, but the actual backtest start/end results instead?
|
||||
btStore.timerange = botStore.activeBot.selectedBacktestResult.timerange;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => botStore.activeBot.selectedBacktestResultKey,
|
||||
() => {
|
||||
selectBacktestResult();
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => botStore.activeBot.getState());
|
||||
watch(
|
||||
() => botStore.activeBot.backtestRunning,
|
||||
() => {
|
||||
if (botStore.activeBot.backtestRunning === true) {
|
||||
pollInterval.value = window.setInterval(botStore.activeBot.pollBacktest, 1000);
|
||||
} else if (pollInterval.value) {
|
||||
clearInterval(pollInterval.value);
|
||||
pollInterval.value = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-column pt-1 me-1" style="height: calc(100vh - 60px)">
|
||||
<div>
|
||||
|
@ -151,78 +223,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBtStore } from '@/stores/btStore';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
enum BtRunModes {
|
||||
run = 'run',
|
||||
results = 'results',
|
||||
visualize = 'visualize',
|
||||
visualizesummary = 'visualize-summary',
|
||||
compareresults = 'compare-results',
|
||||
historicresults = 'historicResults',
|
||||
}
|
||||
|
||||
const botStore = useBotStore();
|
||||
const btStore = useBtStore();
|
||||
|
||||
const hasBacktestResult = computed(() =>
|
||||
botStore.activeBot.backtestHistory
|
||||
? Object.keys(botStore.activeBot.backtestHistory).length !== 0
|
||||
: false,
|
||||
);
|
||||
const hasMultiBacktestResult = computed(() =>
|
||||
botStore.activeBot.backtestHistory
|
||||
? Object.keys(botStore.activeBot.backtestHistory).length > 1
|
||||
: false,
|
||||
);
|
||||
|
||||
const timeframe = computed((): string => {
|
||||
try {
|
||||
return botStore.activeBot.selectedBacktestResult.timeframe;
|
||||
} catch (err) {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
const showLeftBar = ref(false);
|
||||
|
||||
const btFormMode = ref<BtRunModes>(BtRunModes.run);
|
||||
const pollInterval = ref<number | null>(null);
|
||||
|
||||
const selectBacktestResult = () => {
|
||||
// Set parameters for this result
|
||||
btStore.strategy = botStore.activeBot.selectedBacktestResult.strategy_name;
|
||||
botStore.activeBot.getStrategy(btStore.strategy);
|
||||
btStore.selectedTimeframe = botStore.activeBot.selectedBacktestResult.timeframe;
|
||||
btStore.selectedDetailTimeframe =
|
||||
botStore.activeBot.selectedBacktestResult.timeframe_detail || '';
|
||||
// TODO: maybe this should not use timerange, but the actual backtest start/end results instead?
|
||||
btStore.timerange = botStore.activeBot.selectedBacktestResult.timerange;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => botStore.activeBot.selectedBacktestResultKey,
|
||||
() => {
|
||||
selectBacktestResult();
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => botStore.activeBot.getState());
|
||||
watch(
|
||||
() => botStore.activeBot.backtestRunning,
|
||||
() => {
|
||||
if (botStore.activeBot.backtestRunning === true) {
|
||||
pollInterval.value = window.setInterval(botStore.activeBot.pollBacktest, 1000);
|
||||
} else if (pollInterval.value) {
|
||||
clearInterval(pollInterval.value);
|
||||
pollInterval.value = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bt-running-label {
|
||||
position: absolute;
|
||||
|
|
|
@ -1,38 +1,3 @@
|
|||
<template>
|
||||
<div class="d-flex flex-column h-100">
|
||||
<!-- <div v-if="isWebserverMode" class="me-auto ms-3"> -->
|
||||
<!-- Currently only available in Webserver mode -->
|
||||
<!-- <b-form-checkbox v-model="historicView">HistoricData</b-form-checkbox> -->
|
||||
<!-- </div> -->
|
||||
<div v-if="botStore.activeBot.isWebserverMode" class="mx-md-3 mt-2">
|
||||
<div class="d-flex flex-wrap mx-1 gap-1 gap-md-2">
|
||||
<div class="col-12 col-md-3 text-start me-md-1">
|
||||
<span>Strategy</span>
|
||||
<StrategySelect v-model="strategy" class="mt-1"></StrategySelect>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 text-start">
|
||||
<span>Timeframe</span>
|
||||
<TimeframeSelect v-model="selectedTimeframe" class="mt-1" />
|
||||
</div>
|
||||
<TimeRangeSelect v-model="timerange"></TimeRangeSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-md-2 mt-2 pb-1 h-100">
|
||||
<CandleChartContainer
|
||||
:available-pairs="availablePairs"
|
||||
:historic-view="botStore.activeBot.isWebserverMode"
|
||||
:timeframe="finalTimeframe"
|
||||
:trades="botStore.activeBot.trades"
|
||||
:timerange="botStore.activeBot.isWebserverMode ? timerange : ''"
|
||||
:strategy="botStore.activeBot.isWebserverMode ? strategy : ''"
|
||||
:plot-config-modal="false"
|
||||
>
|
||||
</CandleChartContainer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
|
@ -76,4 +41,37 @@ onMounted(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<template>
|
||||
<div class="d-flex flex-column h-100">
|
||||
<!-- <div v-if="isWebserverMode" class="me-auto ms-3"> -->
|
||||
<!-- Currently only available in Webserver mode -->
|
||||
<!-- <b-form-checkbox v-model="historicView">HistoricData</b-form-checkbox> -->
|
||||
<!-- </div> -->
|
||||
<div v-if="botStore.activeBot.isWebserverMode" class="mx-md-3 mt-2">
|
||||
<div class="d-flex flex-wrap mx-1 gap-1 gap-md-2">
|
||||
<div class="col-12 col-md-3 text-start me-md-1">
|
||||
<span>Strategy</span>
|
||||
<StrategySelect v-model="strategy" class="mt-1"></StrategySelect>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 text-start">
|
||||
<span>Timeframe</span>
|
||||
<TimeframeSelect v-model="selectedTimeframe" class="mt-1" />
|
||||
</div>
|
||||
<TimeRangeSelect v-model="timerange"></TimeRangeSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-md-2 mt-2 pb-1 h-100">
|
||||
<CandleChartContainer
|
||||
:available-pairs="availablePairs"
|
||||
:historic-view="botStore.activeBot.isWebserverMode"
|
||||
:timeframe="finalTimeframe"
|
||||
:trades="botStore.activeBot.trades"
|
||||
:timerange="botStore.activeBot.isWebserverMode ? timerange : ''"
|
||||
:strategy="botStore.activeBot.isWebserverMode ? strategy : ''"
|
||||
:plot-config-modal="false"
|
||||
>
|
||||
</CandleChartContainer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,78 @@
|
|||
<script setup lang="ts">
|
||||
import { DashboardLayout, findGridLayout, useLayoutStore } from '@/stores/layout';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { GridItemData } from '@/types';
|
||||
|
||||
const botStore = useBotStore();
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
const currentBreakpoint = ref('');
|
||||
|
||||
function breakpointChanged(newBreakpoint: string) {
|
||||
// console.log('breakpoint:', newBreakpoint);
|
||||
currentBreakpoint.value = newBreakpoint;
|
||||
}
|
||||
const isResizableLayout = computed(() =>
|
||||
['', 'sm', 'md', 'lg', 'xl'].includes(currentBreakpoint.value),
|
||||
);
|
||||
const isLayoutLocked = computed(() => {
|
||||
return layoutStore.layoutLocked || !isResizableLayout.value;
|
||||
});
|
||||
|
||||
const gridLayoutData = computed((): GridItemData[] => {
|
||||
if (isResizableLayout.value) {
|
||||
return layoutStore.dashboardLayout;
|
||||
}
|
||||
return [...layoutStore.getDashboardLayoutSm];
|
||||
});
|
||||
|
||||
function layoutUpdatedEvent(newLayout) {
|
||||
if (isResizableLayout.value) {
|
||||
console.log('newlayout', newLayout);
|
||||
console.log('saving dashboard');
|
||||
layoutStore.dashboardLayout = newLayout;
|
||||
}
|
||||
}
|
||||
|
||||
const gridLayoutDaily = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.dailyChart);
|
||||
});
|
||||
|
||||
const gridLayoutBotComparison = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.botComparison);
|
||||
});
|
||||
|
||||
const gridLayoutAllOpenTrades = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.allOpenTrades);
|
||||
});
|
||||
const gridLayoutAllClosedTrades = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.allClosedTrades);
|
||||
});
|
||||
|
||||
const gridLayoutCumChart = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.cumChartChart);
|
||||
});
|
||||
const gridLayoutProfitDistribution = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.profitDistributionChart);
|
||||
});
|
||||
const gridLayoutTradesLogChart = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.tradesLogChart);
|
||||
});
|
||||
|
||||
const responsiveGridLayouts = computed(() => {
|
||||
return {
|
||||
sm: layoutStore.getDashboardLayoutSm,
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
botStore.allGetDaily({ timescale: 30 });
|
||||
// botStore.activeBot.getTrades();
|
||||
botStore.activeBot.getOpenTrades();
|
||||
botStore.activeBot.getProfit();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GridLayout
|
||||
class="h-100 w-100"
|
||||
|
@ -155,80 +230,3 @@
|
|||
</template>
|
||||
</GridLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DashboardLayout, findGridLayout, useLayoutStore } from '@/stores/layout';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { GridItemData } from '@/types';
|
||||
|
||||
const botStore = useBotStore();
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
const currentBreakpoint = ref('');
|
||||
|
||||
function breakpointChanged(newBreakpoint: string) {
|
||||
// console.log('breakpoint:', newBreakpoint);
|
||||
currentBreakpoint.value = newBreakpoint;
|
||||
}
|
||||
const isResizableLayout = computed(() =>
|
||||
['', 'sm', 'md', 'lg', 'xl'].includes(currentBreakpoint.value),
|
||||
);
|
||||
const isLayoutLocked = computed(() => {
|
||||
return layoutStore.layoutLocked || !isResizableLayout.value;
|
||||
});
|
||||
|
||||
const gridLayoutData = computed((): GridItemData[] => {
|
||||
if (isResizableLayout.value) {
|
||||
return layoutStore.dashboardLayout;
|
||||
}
|
||||
return [...layoutStore.getDashboardLayoutSm];
|
||||
});
|
||||
|
||||
function layoutUpdatedEvent(newLayout) {
|
||||
if (isResizableLayout.value) {
|
||||
console.log('newlayout', newLayout);
|
||||
console.log('saving dashboard');
|
||||
layoutStore.dashboardLayout = newLayout;
|
||||
}
|
||||
}
|
||||
|
||||
const gridLayoutDaily = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.dailyChart);
|
||||
});
|
||||
|
||||
const gridLayoutBotComparison = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.botComparison);
|
||||
});
|
||||
|
||||
const gridLayoutAllOpenTrades = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.allOpenTrades);
|
||||
});
|
||||
const gridLayoutAllClosedTrades = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.allClosedTrades);
|
||||
});
|
||||
|
||||
const gridLayoutCumChart = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.cumChartChart);
|
||||
});
|
||||
const gridLayoutProfitDistribution = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.profitDistributionChart);
|
||||
});
|
||||
const gridLayoutTradesLogChart = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayoutData.value, DashboardLayout.tradesLogChart);
|
||||
});
|
||||
|
||||
const responsiveGridLayouts = computed(() => {
|
||||
return {
|
||||
sm: layoutStore.getDashboardLayoutSm,
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
botStore.allGetDaily({ timescale: 30 });
|
||||
// botStore.activeBot.getTrades();
|
||||
botStore.activeBot.getOpenTrades();
|
||||
botStore.activeBot.getProfit();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div class="home">
|
||||
<div class="d-flex justify-content-center">
|
||||
|
@ -20,8 +22,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
margin-top: 1.5em;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div class="p-1 p-md-4 pe-md-2 h-100">
|
||||
<LogViewer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<BCard header="Freqtrade bot Login">
|
||||
|
@ -6,8 +8,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
max-width: 520px;
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
defineProps({
|
||||
history: { default: false, type: Boolean },
|
||||
});
|
||||
const botStore = useBotStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- <TradeList
|
||||
|
@ -40,13 +49,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
defineProps({
|
||||
history: { default: false, type: Boolean },
|
||||
});
|
||||
const botStore = useBotStore();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<PairlistConfigurator class="pt-4" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
|
|
@ -1,3 +1,31 @@
|
|||
<script setup lang="ts">
|
||||
import { OpenTradeVizOptions, useSettingsStore } from '@/stores/settings';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
import { FtWsMessageTypes } from '@/types/wsMessageTypes';
|
||||
import { ColorPreferences, useColorStore } from '@/stores/colors';
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const colorStore = useColorStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
const timezoneOptions = ['UTC', Intl.DateTimeFormat().resolvedOptions().timeZone];
|
||||
const openTradesOptions = [
|
||||
{ value: OpenTradeVizOptions.showPill, text: 'Show pill in icon' },
|
||||
{ value: OpenTradeVizOptions.asTitle, text: 'Show in title' },
|
||||
{ value: OpenTradeVizOptions.noOpenTrades, text: "Don't show open trades in header" },
|
||||
];
|
||||
const colorPreferenceOptions = [
|
||||
{ value: ColorPreferences.GREEN_UP, text: 'Green Up/Red Down' },
|
||||
{ value: ColorPreferences.RED_UP, text: 'Green Down/Red Up' },
|
||||
];
|
||||
|
||||
const resetDynamicLayout = () => {
|
||||
layoutStore.resetTradingLayout();
|
||||
layoutStore.resetDashboardLayout();
|
||||
showAlert('Layouts have been reset.');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container mt-3">
|
||||
<BCard header="FreqUI Settings">
|
||||
|
@ -122,34 +150,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { OpenTradeVizOptions, useSettingsStore } from '@/stores/settings';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
import { FtWsMessageTypes } from '@/types/wsMessageTypes';
|
||||
import { ColorPreferences, useColorStore } from '@/stores/colors';
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const colorStore = useColorStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
const timezoneOptions = ['UTC', Intl.DateTimeFormat().resolvedOptions().timeZone];
|
||||
const openTradesOptions = [
|
||||
{ value: OpenTradeVizOptions.showPill, text: 'Show pill in icon' },
|
||||
{ value: OpenTradeVizOptions.asTitle, text: 'Show in title' },
|
||||
{ value: OpenTradeVizOptions.noOpenTrades, text: "Don't show open trades in header" },
|
||||
];
|
||||
const colorPreferenceOptions = [
|
||||
{ value: ColorPreferences.GREEN_UP, text: 'Green Up/Red Down' },
|
||||
{ value: ColorPreferences.RED_UP, text: 'Green Down/Red Up' },
|
||||
];
|
||||
|
||||
const resetDynamicLayout = () => {
|
||||
layoutStore.resetTradingLayout();
|
||||
layoutStore.resetDashboardLayout();
|
||||
showAlert('Layouts have been reset.');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.color-candle-arrows {
|
||||
margin-left: -0.5rem;
|
||||
|
|
|
@ -1,3 +1,57 @@
|
|||
<script setup lang="ts">
|
||||
import { GridItemData } from '@/types';
|
||||
|
||||
import { useLayoutStore, findGridLayout, TradeLayout } from '@/stores/layout';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
const currentBreakpoint = ref('');
|
||||
|
||||
const breakpointChanged = (newBreakpoint: string) => {
|
||||
// console.log('breakpoint:', newBreakpoint);
|
||||
currentBreakpoint.value = newBreakpoint;
|
||||
};
|
||||
const isResizableLayout = computed(() =>
|
||||
['', 'sm', 'md', 'lg', 'xl'].includes(currentBreakpoint.value),
|
||||
);
|
||||
const isLayoutLocked = computed(() => {
|
||||
return layoutStore.layoutLocked || !isResizableLayout.value;
|
||||
});
|
||||
const gridLayoutData = computed((): GridItemData[] => {
|
||||
if (isResizableLayout.value) {
|
||||
return layoutStore.tradingLayout;
|
||||
}
|
||||
return [...layoutStore.getTradingLayoutSm];
|
||||
});
|
||||
|
||||
const gridLayoutMultiPane = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.multiPane);
|
||||
});
|
||||
|
||||
const gridLayoutOpenTrades = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.openTrades);
|
||||
});
|
||||
|
||||
const gridLayoutTradeHistory = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.tradeHistory);
|
||||
});
|
||||
|
||||
const gridLayoutTradeDetail = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.tradeDetail);
|
||||
});
|
||||
|
||||
const gridLayoutChartView = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.chartView);
|
||||
});
|
||||
|
||||
const responsiveGridLayouts = computed(() => {
|
||||
return {
|
||||
sm: layoutStore.getTradingLayoutSm,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GridLayout
|
||||
class="h-100 w-100"
|
||||
|
@ -145,58 +199,4 @@
|
|||
</GridLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { GridItemData } from '@/types';
|
||||
|
||||
import { useLayoutStore, findGridLayout, TradeLayout } from '@/stores/layout';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
const currentBreakpoint = ref('');
|
||||
|
||||
const breakpointChanged = (newBreakpoint: string) => {
|
||||
// console.log('breakpoint:', newBreakpoint);
|
||||
currentBreakpoint.value = newBreakpoint;
|
||||
};
|
||||
const isResizableLayout = computed(() =>
|
||||
['', 'sm', 'md', 'lg', 'xl'].includes(currentBreakpoint.value),
|
||||
);
|
||||
const isLayoutLocked = computed(() => {
|
||||
return layoutStore.layoutLocked || !isResizableLayout.value;
|
||||
});
|
||||
const gridLayoutData = computed((): GridItemData[] => {
|
||||
if (isResizableLayout.value) {
|
||||
return layoutStore.tradingLayout;
|
||||
}
|
||||
return [...layoutStore.getTradingLayoutSm];
|
||||
});
|
||||
|
||||
const gridLayoutMultiPane = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.multiPane);
|
||||
});
|
||||
|
||||
const gridLayoutOpenTrades = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.openTrades);
|
||||
});
|
||||
|
||||
const gridLayoutTradeHistory = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.tradeHistory);
|
||||
});
|
||||
|
||||
const gridLayoutTradeDetail = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.tradeDetail);
|
||||
});
|
||||
|
||||
const gridLayoutChartView = computed(() => {
|
||||
return findGridLayout(gridLayoutData.value, TradeLayout.chartView);
|
||||
});
|
||||
|
||||
const responsiveGridLayouts = computed(() => {
|
||||
return {
|
||||
sm: layoutStore.getTradingLayoutSm,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
Loading…
Reference in New Issue
Block a user