mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-22 11:05:17 +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">
|
<script setup lang="ts">
|
||||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||||
import { TableField } from 'bootstrap-vue-next';
|
import { TableField } from 'bootstrap-vue-next';
|
||||||
|
@ -105,3 +71,37 @@ onMounted(() => {
|
||||||
refreshSummary();
|
refreshSummary();
|
||||||
});
|
});
|
||||||
</script>
|
</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>
|
<template>
|
||||||
<div class="d-flex align-items-center ms-2">
|
<div class="d-flex align-items-center ms-2">
|
||||||
<BFormCheckbox
|
<BFormCheckbox
|
||||||
|
@ -17,18 +31,4 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<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">
|
<script setup lang="ts">
|
||||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||||
|
|
||||||
|
@ -50,3 +26,27 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</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">
|
<script setup lang="ts">
|
||||||
import Datepicker from '@vuepic/vue-datepicker';
|
import Datepicker from '@vuepic/vue-datepicker';
|
||||||
import '@vuepic/vue-datepicker/dist/main.css';
|
import '@vuepic/vue-datepicker/dist/main.css';
|
||||||
|
@ -103,4 +63,44 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</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>
|
<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">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { default: '', type: String },
|
value: { default: '', type: String },
|
||||||
|
@ -52,4 +43,13 @@ const emitSelectedTimeframe = () => {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BFormSelect
|
||||||
|
v-model="selectedTimeframe"
|
||||||
|
placeholder="Use strategy default"
|
||||||
|
:options="availableTimeframes"
|
||||||
|
@change="emitSelectedTimeframe"
|
||||||
|
></BFormSelect>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<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>
|
<template>
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<BButton
|
<BButton
|
||||||
|
@ -75,31 +102,4 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<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>
|
<template>
|
||||||
<div class="container text-start">
|
<div class="container text-start">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -139,17 +150,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<style scoped>
|
||||||
.detail-header {
|
.detail-header {
|
||||||
border-bottom: 1px solid;
|
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">
|
<script setup lang="ts">
|
||||||
import { MultiDeletePayload, MultiForcesellPayload, Trade } from '@/types';
|
import { MultiDeletePayload, MultiForcesellPayload, Trade } from '@/types';
|
||||||
|
|
||||||
|
@ -315,6 +216,105 @@ watch(
|
||||||
);
|
);
|
||||||
</script>
|
</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>
|
<style lang="scss" scoped>
|
||||||
.card-body {
|
.card-body {
|
||||||
padding: 0 0.2em;
|
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>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<BListGroup>
|
<BListGroup>
|
||||||
|
@ -57,46 +97,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<style scoped>
|
||||||
.list-group {
|
.list-group {
|
||||||
text-align: left;
|
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">
|
<script setup lang="ts">
|
||||||
import { Trade } from '@/types';
|
import { Trade } from '@/types';
|
||||||
|
|
||||||
|
@ -60,4 +51,13 @@ const profitDesc = computed((): string => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ProfitPill
|
||||||
|
:profit-ratio="profitRatio"
|
||||||
|
:profit-abs="profitAbs"
|
||||||
|
:profit-desc="profitDesc"
|
||||||
|
:stake-currency="trade.quote_currency || 'USDT'"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<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>
|
<template>
|
||||||
<div class="copy-container position-relative">
|
<div class="copy-container position-relative">
|
||||||
<i-mdi-content-copy
|
<i-mdi-content-copy
|
||||||
|
@ -10,17 +21,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<style lang="scss" scoped>
|
||||||
.copy-container {
|
.copy-container {
|
||||||
.copy-button {
|
.copy-button {
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
<template>
|
|
||||||
<span :title="timezoneTooltip">{{ formattedDate }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
date: { required: true, type: Number },
|
date: { required: true, type: Number },
|
||||||
|
@ -29,4 +25,8 @@ const timezoneTooltip = computed((): string => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span :title="timezoneTooltip">{{ formattedDate }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<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">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
|
@ -142,3 +80,65 @@ function saveNewName() {
|
||||||
mode.value = EditState.None;
|
mode.value = EditState.None;
|
||||||
}
|
}
|
||||||
</script>
|
</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">
|
<script setup lang="ts">
|
||||||
defineProps({
|
defineProps({
|
||||||
hint: { type: String, required: true },
|
hint: { type: String, required: true },
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :title="hint">
|
||||||
|
<i-mdi-information-outline />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<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">
|
<script setup lang="ts">
|
||||||
export interface MsgBoxObject {
|
export interface MsgBoxObject {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -41,4 +26,19 @@ const show = (msg: MsgBoxObject) => {
|
||||||
defineExpose({ show });
|
defineExpose({ show });
|
||||||
</script>
|
</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>
|
<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">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
profitRatio: { required: false, default: undefined, type: Number },
|
profitRatio: { required: false, default: undefined, type: Number },
|
||||||
|
@ -47,6 +26,27 @@ const profitString = computed((): string => {
|
||||||
});
|
});
|
||||||
</script>
|
</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">
|
<style scoped lang="scss">
|
||||||
.profit-pill {
|
.profit-pill {
|
||||||
border: 2px solid $color-loss;
|
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">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
profit: { type: Number, required: true },
|
profit: { type: Number, required: true },
|
||||||
|
@ -13,6 +7,12 @@ const isProfitable = computed(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="d-inline-block">
|
||||||
|
<div :class="isProfitable ? 'triangle-up' : 'triangle-down'"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.triangle-up {
|
.triangle-up {
|
||||||
width: 0;
|
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>
|
<template>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="d-flex justify-content-between me-2" :class="classLabel">
|
<div class="d-flex justify-content-between me-2" :class="classLabel">
|
||||||
|
@ -9,14 +18,3 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<template>
|
||||||
<div class="card h-100 w-100">
|
<div class="card h-100 w-100">
|
||||||
<div class="drag-header card-header">
|
<div class="drag-header card-header">
|
||||||
|
@ -11,12 +17,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
defineProps({
|
|
||||||
header: { required: false, type: String, default: '' },
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.card-header {
|
.card-header {
|
||||||
padding: 0.25rem 0.5rem;
|
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>
|
<template>
|
||||||
<header>
|
<header>
|
||||||
<BNavbar toggleable="sm" dark variant="primary">
|
<BNavbar toggleable="sm" dark variant="primary">
|
||||||
|
@ -129,104 +227,6 @@
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</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>
|
<style lang="scss" scoped>
|
||||||
.logo {
|
.logo {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||||
|
|
||||||
|
const botStore = useBotStore();
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<footer class="d-md-none">
|
<footer class="d-md-none">
|
||||||
<!-- Only visible on xs (phone) viewport! -->
|
<!-- Only visible on xs (phone) viewport! -->
|
||||||
|
@ -47,12 +53,6 @@
|
||||||
</footer>
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
|
||||||
|
|
||||||
const botStore = useBotStore();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
[data-theme='dark'] {
|
[data-theme='dark'] {
|
||||||
.router-link-active,
|
.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>
|
<template>
|
||||||
<div class="d-flex flex-column pt-1 me-1" style="height: calc(100vh - 60px)">
|
<div class="d-flex flex-column pt-1 me-1" style="height: calc(100vh - 60px)">
|
||||||
<div>
|
<div>
|
||||||
|
@ -151,78 +223,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<style lang="scss" scoped>
|
||||||
.bt-running-label {
|
.bt-running-label {
|
||||||
position: absolute;
|
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">
|
<script setup lang="ts">
|
||||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||||
|
|
||||||
|
@ -76,4 +41,37 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</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>
|
<template>
|
||||||
<GridLayout
|
<GridLayout
|
||||||
class="h-100 w-100"
|
class="h-100 w-100"
|
||||||
|
@ -155,80 +230,3 @@
|
||||||
</template>
|
</template>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
</template>
|
</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>
|
<template>
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
|
@ -20,8 +22,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.home {
|
.home {
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-1 p-md-4 pe-md-2 h-100">
|
<div class="p-1 p-md-4 pe-md-2 h-100">
|
||||||
<LogViewer />
|
<LogViewer />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<BCard header="Freqtrade bot Login">
|
<BCard header="Freqtrade bot Login">
|
||||||
|
@ -6,8 +8,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.container {
|
.container {
|
||||||
max-width: 520px;
|
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>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- <TradeList
|
<!-- <TradeList
|
||||||
|
@ -40,13 +49,4 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
history: { default: false, type: Boolean },
|
|
||||||
});
|
|
||||||
const botStore = useBotStore();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PairlistConfigurator class="pt-4" />
|
<PairlistConfigurator class="pt-4" />
|
||||||
</template>
|
</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>
|
<template>
|
||||||
<div class="container mt-3">
|
<div class="container mt-3">
|
||||||
<BCard header="FreqUI Settings">
|
<BCard header="FreqUI Settings">
|
||||||
|
@ -122,34 +150,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<style lang="scss" scoped>
|
||||||
.color-candle-arrows {
|
.color-candle-arrows {
|
||||||
margin-left: -0.5rem;
|
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>
|
<template>
|
||||||
<GridLayout
|
<GridLayout
|
||||||
class="h-100 w-100"
|
class="h-100 w-100"
|
||||||
|
@ -145,58 +199,4 @@
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
</template>
|
</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>
|
<style scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user