mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-10 02:11:57 +00:00
chore: update block-order in components
script before template.
This commit is contained in:
parent
8b40c2a862
commit
dc3553bb3e
|
@ -1,21 +1,3 @@
|
|||
<template>
|
||||
<div class="d-flex flex-row">
|
||||
<BFormGroup class="flex-grow-1" :label="label" label-for="indicatorSelector">
|
||||
<VSelect
|
||||
v-model="selAvailableIndicator"
|
||||
:options="columns"
|
||||
size="sm"
|
||||
:clearable="false"
|
||||
@option:selected="emitIndicator"
|
||||
>
|
||||
</VSelect>
|
||||
</BFormGroup>
|
||||
<BButton size="sm" title="Abort" class="ms-1 mt-auto" variant="secondary" @click="abort">
|
||||
<i-mdi-close />
|
||||
</BButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import VSelect from 'vue-select';
|
||||
|
||||
|
@ -52,4 +34,22 @@ watch(
|
|||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-row">
|
||||
<BFormGroup class="flex-grow-1" :label="label" label-for="indicatorSelector">
|
||||
<VSelect
|
||||
v-model="selAvailableIndicator"
|
||||
:options="columns"
|
||||
size="sm"
|
||||
:clearable="false"
|
||||
@option:selected="emitIndicator"
|
||||
>
|
||||
</VSelect>
|
||||
</BFormGroup>
|
||||
<BButton size="sm" title="Abort" class="ms-1 mt-auto" variant="secondary" @click="abort">
|
||||
<i-mdi-close />
|
||||
</BButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,29 +1,3 @@
|
|||
<template>
|
||||
<div class="d-flex flex-column h-100 position-relative">
|
||||
<div class="flex-grow-1">
|
||||
<ECharts v-if="trades" :option="chartOptions" autoresize :theme="settingsStore.chartTheme" />
|
||||
</div>
|
||||
<BFormGroup
|
||||
class="z-2"
|
||||
:class="showTitle ? 'ms-5 ps-5' : 'position-absolute'"
|
||||
label="Bins"
|
||||
style="width: 33%; min-width: 12rem"
|
||||
label-for="input-bins"
|
||||
label-cols="6"
|
||||
content-cols="6"
|
||||
size="sm"
|
||||
>
|
||||
<BFormSelect
|
||||
id="input-bins"
|
||||
v-model="settingsStore.profitDistributionBins"
|
||||
size="sm"
|
||||
class="mt-1"
|
||||
:options="binOptions"
|
||||
></BFormSelect>
|
||||
</BFormGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ECharts from 'vue-echarts';
|
||||
import { EChartsOption } from 'echarts';
|
||||
|
@ -143,6 +117,32 @@ const chartOptions = computed((): EChartsOption => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-column h-100 position-relative">
|
||||
<div class="flex-grow-1">
|
||||
<ECharts v-if="trades" :option="chartOptions" autoresize :theme="settingsStore.chartTheme" />
|
||||
</div>
|
||||
<BFormGroup
|
||||
class="z-2"
|
||||
:class="showTitle ? 'ms-5 ps-5' : 'position-absolute'"
|
||||
label="Bins"
|
||||
style="width: 33%; min-width: 12rem"
|
||||
label-for="input-bins"
|
||||
label-cols="6"
|
||||
content-cols="6"
|
||||
size="sm"
|
||||
>
|
||||
<BFormSelect
|
||||
id="input-bins"
|
||||
v-model="settingsStore.profitDistributionBins"
|
||||
size="sm"
|
||||
class="mt-1"
|
||||
:options="binOptions"
|
||||
></BFormSelect>
|
||||
</BFormGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.echarts {
|
||||
width: 100%;
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
<template>
|
||||
<ECharts
|
||||
v-if="dailyStats.data"
|
||||
ref="dailyChart"
|
||||
:option="dailyChartOptions"
|
||||
:theme="settingsStore.chartTheme"
|
||||
:style="{ height: width * 0.6 + 'px' }"
|
||||
autoresize
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ECharts from 'vue-echarts';
|
||||
// import { EChartsOption } from 'echarts';
|
||||
|
@ -162,6 +151,17 @@ const dailyChartOptions: ComputedRef<EChartsOption> = computed(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ECharts
|
||||
v-if="dailyStats.data"
|
||||
ref="dailyChart"
|
||||
:option="dailyChartOptions"
|
||||
:theme="settingsStore.chartTheme"
|
||||
:style="{ height: width * 0.6 + 'px' }"
|
||||
autoresize
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.echarts {
|
||||
min-height: 240px;
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
<template>
|
||||
<ECharts
|
||||
v-if="trades.length > 0"
|
||||
:option="chartOptions"
|
||||
autoresize
|
||||
:theme="settingsStore.chartTheme"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ECharts from 'vue-echarts';
|
||||
import { EChartsOption } from 'echarts';
|
||||
|
@ -178,6 +169,15 @@ const chartOptions = computed((): EChartsOption => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ECharts
|
||||
v-if="trades.length > 0"
|
||||
:option="chartOptions"
|
||||
autoresize
|
||||
:theme="settingsStore.chartTheme"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.echarts {
|
||||
width: 100%;
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
<script setup lang="ts">
|
||||
import MessageBox, { MsgBoxObject } from '@/components/general/MessageBox.vue';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { BacktestHistoryEntry } from '@/types';
|
||||
import InfoBox from '../general/InfoBox.vue';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const msgBox = ref<typeof MessageBox>();
|
||||
const filterText = ref('');
|
||||
const filterTextDebounced = refDebounced(filterText, 350, { maxWait: 1000 });
|
||||
|
||||
onMounted(() => {
|
||||
botStore.activeBot.getBacktestHistory();
|
||||
});
|
||||
|
||||
function deleteBacktestResult(result: BacktestHistoryEntry) {
|
||||
const msg: MsgBoxObject = {
|
||||
title: 'Delete result',
|
||||
message: `Delete result ${result.filename} from disk?`,
|
||||
accept: () => {
|
||||
botStore.activeBot.deleteBacktestHistoryResult(result);
|
||||
},
|
||||
};
|
||||
msgBox.value?.show(msg);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<button
|
||||
|
@ -104,33 +131,6 @@
|
|||
<MessageBox ref="msgBox" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MessageBox, { MsgBoxObject } from '@/components/general/MessageBox.vue';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { BacktestHistoryEntry } from '@/types';
|
||||
import InfoBox from '../general/InfoBox.vue';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const msgBox = ref<typeof MessageBox>();
|
||||
const filterText = ref('');
|
||||
const filterTextDebounced = refDebounced(filterText, 350, { maxWait: 1000 });
|
||||
|
||||
onMounted(() => {
|
||||
botStore.activeBot.getBacktestHistory();
|
||||
});
|
||||
|
||||
function deleteBacktestResult(result: BacktestHistoryEntry) {
|
||||
const msg: MsgBoxObject = {
|
||||
title: 'Delete result',
|
||||
message: `Delete result ${result.filename} from disk?`,
|
||||
accept: () => {
|
||||
botStore.activeBot.deleteBacktestHistoryResult(result);
|
||||
},
|
||||
};
|
||||
msgBox.value?.show(msg);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-rounded-corners {
|
||||
box-shadow: 0 0 0 1px var(--bs-border-color);
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import { StrategyBacktestResult } from '@/types';
|
||||
|
||||
import { TableField } from 'bootstrap-vue-next';
|
||||
|
||||
const props = defineProps({
|
||||
backtestResult: { required: true, type: Object as () => StrategyBacktestResult },
|
||||
});
|
||||
|
||||
const backtestResultStats = computed(() => {
|
||||
const tmp = generateBacktestMetricRows(props.backtestResult);
|
||||
return formatObjectForTable({ value: tmp }, 'metric');
|
||||
});
|
||||
|
||||
const backtestResultSettings = computed(() => {
|
||||
// Transpose Result into readable format
|
||||
const tmp = generateBacktestSettingRows(props.backtestResult);
|
||||
|
||||
return formatObjectForTable({ value: tmp }, 'setting');
|
||||
});
|
||||
const backtestResultFields: TableField[] = [
|
||||
{ key: 'metric', label: 'Metric' },
|
||||
{ key: 'value', label: 'Value' },
|
||||
];
|
||||
|
||||
const backtestsettingFields: TableField[] = [
|
||||
{ key: 'setting', label: 'Setting' },
|
||||
{ key: 'value', label: 'Value' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="px-0 mw-100">
|
||||
<div class="d-flex justify-content-center">
|
||||
|
@ -72,35 +103,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { StrategyBacktestResult } from '@/types';
|
||||
|
||||
import { TableField } from 'bootstrap-vue-next';
|
||||
|
||||
const props = defineProps({
|
||||
backtestResult: { required: true, type: Object as () => StrategyBacktestResult },
|
||||
});
|
||||
|
||||
const backtestResultStats = computed(() => {
|
||||
const tmp = generateBacktestMetricRows(props.backtestResult);
|
||||
return formatObjectForTable({ value: tmp }, 'metric');
|
||||
});
|
||||
|
||||
const backtestResultSettings = computed(() => {
|
||||
// Transpose Result into readable format
|
||||
const tmp = generateBacktestSettingRows(props.backtestResult);
|
||||
|
||||
return formatObjectForTable({ value: tmp }, 'setting');
|
||||
});
|
||||
const backtestResultFields: TableField[] = [
|
||||
{ key: 'metric', label: 'Metric' },
|
||||
{ key: 'value', label: 'Value' },
|
||||
];
|
||||
|
||||
const backtestsettingFields: TableField[] = [
|
||||
{ key: 'setting', label: 'Setting' },
|
||||
{ key: 'value', label: 'Value' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -1,3 +1,28 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
import { ChartSliderPosition, Trade } from '@/types';
|
||||
|
||||
defineProps({
|
||||
timeframe: { required: true, type: String },
|
||||
strategy: { required: true, type: String },
|
||||
freqaiModel: { required: false, default: undefined, type: String },
|
||||
timerange: { required: true, type: String },
|
||||
pairlist: { required: true, type: Array as () => string[] },
|
||||
trades: { required: true, type: Array as () => Trade[] },
|
||||
});
|
||||
const botStore = useBotStore();
|
||||
const isBarVisible = ref({ right: true, left: true });
|
||||
const sliderPosition = ref<ChartSliderPosition>();
|
||||
|
||||
const navigateChartToTrade = (trade: Trade) => {
|
||||
sliderPosition.value = {
|
||||
startValue: trade.open_timestamp,
|
||||
endValue: trade.close_timestamp,
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex flex-row mb-1 align-items-center">
|
||||
|
@ -70,31 +95,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
import { ChartSliderPosition, Trade } from '@/types';
|
||||
|
||||
defineProps({
|
||||
timeframe: { required: true, type: String },
|
||||
strategy: { required: true, type: String },
|
||||
freqaiModel: { required: false, default: undefined, type: String },
|
||||
timerange: { required: true, type: String },
|
||||
pairlist: { required: true, type: Array as () => string[] },
|
||||
trades: { required: true, type: Array as () => Trade[] },
|
||||
});
|
||||
const botStore = useBotStore();
|
||||
const isBarVisible = ref({ right: true, left: true });
|
||||
const sliderPosition = ref<ChartSliderPosition>();
|
||||
|
||||
const navigateChartToTrade = (trade: Trade) => {
|
||||
sliderPosition.value = {
|
||||
startValue: trade.open_timestamp,
|
||||
endValue: trade.close_timestamp,
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.candle-chart-container {
|
||||
// TODO: Rough estimate - still to fix correctly
|
||||
|
|
|
@ -1,32 +1,3 @@
|
|||
<template>
|
||||
<div class="px-0 mw-100">
|
||||
<div class="d-flex justify-content-center">
|
||||
<h3>Backtest-result comparison</h3>
|
||||
</div>
|
||||
|
||||
<!-- <div class="d-flex">
|
||||
<div v-for="[key, result] in Object.entries(backtestResults)" :key="key" class="border m-1">
|
||||
<BacktestResultSelectEntry :backtest-result="result" />
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="d-flex flex-column text-start ms-0 me-2 gap-2">
|
||||
<div class="d-flex flex-column flex-xl-row">
|
||||
<div class="px-0 px-xl-0 pt-2 pt-xl-0 ps-xl-1 flex-fill">
|
||||
<BTable bordered :items="backtestResultStats" :fields="backtestResultFields">
|
||||
<template
|
||||
v-for="[key, result] in Object.entries(backtestResults)"
|
||||
#[`head(${key})`]
|
||||
:key="key"
|
||||
>
|
||||
<BacktestResultSelectEntry :backtest-result="result" />
|
||||
</template>
|
||||
</BTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BacktestResultInMemory } from '@/types';
|
||||
|
||||
|
@ -56,4 +27,33 @@ const backtestResultFields = computed<TableField[]>(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="px-0 mw-100">
|
||||
<div class="d-flex justify-content-center">
|
||||
<h3>Backtest-result comparison</h3>
|
||||
</div>
|
||||
|
||||
<!-- <div class="d-flex">
|
||||
<div v-for="[key, result] in Object.entries(backtestResults)" :key="key" class="border m-1">
|
||||
<BacktestResultSelectEntry :backtest-result="result" />
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="d-flex flex-column text-start ms-0 me-2 gap-2">
|
||||
<div class="d-flex flex-column flex-xl-row">
|
||||
<div class="px-0 px-xl-0 pt-2 pt-xl-0 ps-xl-1 flex-fill">
|
||||
<BTable bordered :items="backtestResultStats" :fields="backtestResultFields">
|
||||
<template
|
||||
v-for="[key, result] in Object.entries(backtestResults)"
|
||||
#[`head(${key})`]
|
||||
:key="key"
|
||||
>
|
||||
<BacktestResultSelectEntry :backtest-result="result" />
|
||||
</template>
|
||||
</BTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -1,3 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
import { BacktestResultInMemory, BacktestResultUpdate } from '@/types';
|
||||
|
||||
defineProps({
|
||||
backtestHistory: {
|
||||
required: true,
|
||||
type: Object as () => Record<string, BacktestResultInMemory>,
|
||||
},
|
||||
selectedBacktestResultKey: { required: false, default: '', type: String },
|
||||
canUseModify: { required: false, default: false, type: Boolean },
|
||||
});
|
||||
const emit = defineEmits<{
|
||||
selectionChange: [value: string];
|
||||
removeResult: [value: string];
|
||||
updateResult: [value: BacktestResultUpdate];
|
||||
}>();
|
||||
|
||||
const setBacktestResult = (key: string) => {
|
||||
emit('selectionChange', key);
|
||||
};
|
||||
|
||||
function confirmInput(run_id: string, result: BacktestResultInMemory) {
|
||||
result.metadata.editing = !result.metadata.editing;
|
||||
if (result.metadata.filename) {
|
||||
emit('updateResult', {
|
||||
run_id: run_id,
|
||||
notes: result.metadata.notes ?? '',
|
||||
filename: result.metadata.filename,
|
||||
strategy: result.metadata.strategyName,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container d-flex flex-column align-items-stretch">
|
||||
<h3>Available results:</h3>
|
||||
|
@ -45,38 +79,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BacktestResultInMemory, BacktestResultUpdate } from '@/types';
|
||||
|
||||
defineProps({
|
||||
backtestHistory: {
|
||||
required: true,
|
||||
type: Object as () => Record<string, BacktestResultInMemory>,
|
||||
},
|
||||
selectedBacktestResultKey: { required: false, default: '', type: String },
|
||||
canUseModify: { required: false, default: false, type: Boolean },
|
||||
});
|
||||
const emit = defineEmits<{
|
||||
selectionChange: [value: string];
|
||||
removeResult: [value: string];
|
||||
updateResult: [value: BacktestResultUpdate];
|
||||
}>();
|
||||
|
||||
const setBacktestResult = (key: string) => {
|
||||
emit('selectionChange', key);
|
||||
};
|
||||
|
||||
function confirmInput(run_id: string, result: BacktestResultInMemory) {
|
||||
result.metadata.editing = !result.metadata.editing;
|
||||
if (result.metadata.filename) {
|
||||
emit('updateResult', {
|
||||
run_id: run_id,
|
||||
notes: result.metadata.notes ?? '',
|
||||
filename: result.metadata.filename,
|
||||
strategy: result.metadata.strategyName,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { BacktestResultInMemory } from '@/types';
|
||||
|
||||
defineProps({
|
||||
backtestResult: {
|
||||
required: true,
|
||||
type: Object as () => BacktestResultInMemory,
|
||||
},
|
||||
selectedBacktestResultKey: { required: false, default: '', type: String },
|
||||
canUseModify: { required: false, default: false, type: Boolean },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-column me-2 text-start">
|
||||
<div class="fw-bold">
|
||||
|
@ -13,17 +26,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BacktestResultInMemory } from '@/types';
|
||||
|
||||
defineProps({
|
||||
backtestResult: {
|
||||
required: true,
|
||||
type: Object as () => BacktestResultInMemory,
|
||||
},
|
||||
selectedBacktestResultKey: { required: false, default: '', type: String },
|
||||
canUseModify: { required: false, default: false, type: Boolean },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,3 +1,55 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { BacktestPayload } from '@/types';
|
||||
|
||||
import { useBtStore } from '@/stores/btStore';
|
||||
const botStore = useBotStore();
|
||||
const btStore = useBtStore();
|
||||
|
||||
function clickBacktest() {
|
||||
const btPayload: BacktestPayload = {
|
||||
strategy: btStore.strategy,
|
||||
timerange: btStore.timerange,
|
||||
enable_protections: btStore.enableProtections,
|
||||
};
|
||||
const openTradesInt = parseInt(btStore.maxOpenTrades, 10);
|
||||
if (openTradesInt) {
|
||||
btPayload.max_open_trades = openTradesInt;
|
||||
}
|
||||
if (btStore.stakeAmountUnlimited) {
|
||||
btPayload.stake_amount = 'unlimited';
|
||||
} else {
|
||||
const stakeAmountLoc = Number(btStore.stakeAmount);
|
||||
if (stakeAmountLoc) {
|
||||
btPayload.stake_amount = stakeAmountLoc.toString();
|
||||
}
|
||||
}
|
||||
|
||||
const startingCapitalLoc = Number(btStore.startingCapital);
|
||||
if (startingCapitalLoc) {
|
||||
btPayload.dry_run_wallet = startingCapitalLoc;
|
||||
}
|
||||
|
||||
if (btStore.selectedTimeframe) {
|
||||
btPayload.timeframe = btStore.selectedTimeframe;
|
||||
}
|
||||
if (btStore.selectedDetailTimeframe) {
|
||||
btPayload.timeframe_detail = btStore.selectedDetailTimeframe;
|
||||
}
|
||||
if (!btStore.allowCache) {
|
||||
btPayload.backtest_cache = 'none';
|
||||
}
|
||||
if (btStore.freqAI.enabled) {
|
||||
btPayload.freqaimodel = btStore.freqAI.model;
|
||||
if (btStore.freqAI.identifier !== '') {
|
||||
btPayload.freqai = { identifier: btStore.freqAI.identifier };
|
||||
}
|
||||
}
|
||||
|
||||
botStore.activeBot.startBacktest(btPayload);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-2">
|
||||
<span>Strategy</span>
|
||||
|
@ -199,56 +251,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { BacktestPayload } from '@/types';
|
||||
|
||||
import { useBtStore } from '@/stores/btStore';
|
||||
const botStore = useBotStore();
|
||||
const btStore = useBtStore();
|
||||
|
||||
function clickBacktest() {
|
||||
const btPayload: BacktestPayload = {
|
||||
strategy: btStore.strategy,
|
||||
timerange: btStore.timerange,
|
||||
enable_protections: btStore.enableProtections,
|
||||
};
|
||||
const openTradesInt = parseInt(btStore.maxOpenTrades, 10);
|
||||
if (openTradesInt) {
|
||||
btPayload.max_open_trades = openTradesInt;
|
||||
}
|
||||
if (btStore.stakeAmountUnlimited) {
|
||||
btPayload.stake_amount = 'unlimited';
|
||||
} else {
|
||||
const stakeAmountLoc = Number(btStore.stakeAmount);
|
||||
if (stakeAmountLoc) {
|
||||
btPayload.stake_amount = stakeAmountLoc.toString();
|
||||
}
|
||||
}
|
||||
|
||||
const startingCapitalLoc = Number(btStore.startingCapital);
|
||||
if (startingCapitalLoc) {
|
||||
btPayload.dry_run_wallet = startingCapitalLoc;
|
||||
}
|
||||
|
||||
if (btStore.selectedTimeframe) {
|
||||
btPayload.timeframe = btStore.selectedTimeframe;
|
||||
}
|
||||
if (btStore.selectedDetailTimeframe) {
|
||||
btPayload.timeframe_detail = btStore.selectedDetailTimeframe;
|
||||
}
|
||||
if (!btStore.allowCache) {
|
||||
btPayload.backtest_cache = 'none';
|
||||
}
|
||||
if (btStore.freqAI.enabled) {
|
||||
btPayload.freqaimodel = btStore.freqAI.model;
|
||||
if (btStore.freqAI.identifier !== '') {
|
||||
btPayload.freqai = { identifier: btStore.freqAI.identifier };
|
||||
}
|
||||
}
|
||||
|
||||
botStore.activeBot.startBacktest(btPayload);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,65 +1,3 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
<label class="me-auto h3">Balance</label>
|
||||
<div class="float-end d-flex flex-row">
|
||||
<BButton
|
||||
v-if="canUseBotBalance"
|
||||
size="sm"
|
||||
:title="!showBotOnly ? 'Showing Account balance' : 'Showing Bot balance'"
|
||||
@click="showBotOnly = !showBotOnly"
|
||||
>
|
||||
<i-mdi-robot v-if="showBotOnly" />
|
||||
<i-mdi-bank v-else />
|
||||
</BButton>
|
||||
<BButton
|
||||
size="sm"
|
||||
:title="!hideSmallBalances ? 'Hide small balances' : 'Show all balances'"
|
||||
@click="hideSmallBalances = !hideSmallBalances"
|
||||
>
|
||||
<i-mdi-eye-off v-if="hideSmallBalances" />
|
||||
<i-mdi-eye v-else />
|
||||
</BButton>
|
||||
|
||||
<BButton class="float-end" size="sm" @click="refreshBalance">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
</div>
|
||||
<BalanceChart v-if="balanceCurrencies" :currencies="chartValues" />
|
||||
<div>
|
||||
<p v-if="botStore.activeBot.balance.note">
|
||||
<strong>{{ botStore.activeBot.balance.note }}</strong>
|
||||
</p>
|
||||
<BTable class="table-sm" :items="balanceCurrencies" :fields="tableFields">
|
||||
<template #custom-foot>
|
||||
<td class="pt-1"><strong>Total</strong></td>
|
||||
<td class="pt-1">
|
||||
<span
|
||||
class="font-italic"
|
||||
:title="`Increase over initial capital of ${formatCurrency(
|
||||
botStore.activeBot.balance.starting_capital,
|
||||
)} ${botStore.activeBot.balance.stake}`"
|
||||
>
|
||||
{{ formatPercent(botStore.activeBot.balance.starting_capital_ratio) }}
|
||||
</span>
|
||||
</td>
|
||||
<!-- this is a computed prop that adds up all the expenses in the visible rows -->
|
||||
<td class="pt-1">
|
||||
<strong>
|
||||
{{
|
||||
showBotOnly && canUseBotBalance
|
||||
? formatCurrency(botStore.activeBot.balance.total_bot)
|
||||
: formatCurrency(botStore.activeBot.balance.total)
|
||||
}}
|
||||
</strong>
|
||||
</td>
|
||||
</template>
|
||||
</BTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { BalanceValues } from '@/types';
|
||||
|
@ -132,3 +70,65 @@ onMounted(() => {
|
|||
refreshBalance();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
<label class="me-auto h3">Balance</label>
|
||||
<div class="float-end d-flex flex-row">
|
||||
<BButton
|
||||
v-if="canUseBotBalance"
|
||||
size="sm"
|
||||
:title="!showBotOnly ? 'Showing Account balance' : 'Showing Bot balance'"
|
||||
@click="showBotOnly = !showBotOnly"
|
||||
>
|
||||
<i-mdi-robot v-if="showBotOnly" />
|
||||
<i-mdi-bank v-else />
|
||||
</BButton>
|
||||
<BButton
|
||||
size="sm"
|
||||
:title="!hideSmallBalances ? 'Hide small balances' : 'Show all balances'"
|
||||
@click="hideSmallBalances = !hideSmallBalances"
|
||||
>
|
||||
<i-mdi-eye-off v-if="hideSmallBalances" />
|
||||
<i-mdi-eye v-else />
|
||||
</BButton>
|
||||
|
||||
<BButton class="float-end" size="sm" @click="refreshBalance">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
</div>
|
||||
<BalanceChart v-if="balanceCurrencies" :currencies="chartValues" />
|
||||
<div>
|
||||
<p v-if="botStore.activeBot.balance.note">
|
||||
<strong>{{ botStore.activeBot.balance.note }}</strong>
|
||||
</p>
|
||||
<BTable class="table-sm" :items="balanceCurrencies" :fields="tableFields">
|
||||
<template #custom-foot>
|
||||
<td class="pt-1"><strong>Total</strong></td>
|
||||
<td class="pt-1">
|
||||
<span
|
||||
class="font-italic"
|
||||
:title="`Increase over initial capital of ${formatCurrency(
|
||||
botStore.activeBot.balance.starting_capital,
|
||||
)} ${botStore.activeBot.balance.stake}`"
|
||||
>
|
||||
{{ formatPercent(botStore.activeBot.balance.starting_capital_ratio) }}
|
||||
</span>
|
||||
</td>
|
||||
<!-- this is a computed prop that adds up all the expenses in the visible rows -->
|
||||
<td class="pt-1">
|
||||
<strong>
|
||||
{{
|
||||
showBotOnly && canUseBotBalance
|
||||
? formatCurrency(botStore.activeBot.balance.total_bot)
|
||||
: formatCurrency(botStore.activeBot.balance.total)
|
||||
}}
|
||||
</strong>
|
||||
</td>
|
||||
</template>
|
||||
</BTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,76 +1,3 @@
|
|||
<template>
|
||||
<BTable
|
||||
ref="tradesTable"
|
||||
small
|
||||
hover
|
||||
show-empty
|
||||
primary-key="botId"
|
||||
:items="tableItems"
|
||||
:fields="tableFields"
|
||||
>
|
||||
<template #cell(botName)="{ item, value }">
|
||||
<div class="d-flex flex-row">
|
||||
<BFormCheckbox
|
||||
v-if="item.botId && botStore.botCount > 1"
|
||||
v-model="
|
||||
botStore.botStores[(item as unknown as ComparisonTableItems).botId ?? ''].isSelected
|
||||
"
|
||||
title="Show this bot in Dashboard"
|
||||
>{{ value }}</BFormCheckbox
|
||||
>
|
||||
<BFormCheckbox
|
||||
v-if="!item.botId && botStore.botCount > 1"
|
||||
v-model="allToggled"
|
||||
title="Toggle all bots"
|
||||
>{{ value }}</BFormCheckbox
|
||||
>
|
||||
<span v-if="botStore.botCount <= 1">{{ value }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(profitOpen)="{ item }">
|
||||
<ProfitPill
|
||||
v-if="item.profitOpen && item.botId != 'Summary'"
|
||||
:profit-ratio="(item as unknown as ComparisonTableItems).profitOpenRatio"
|
||||
:profit-abs="(item as unknown as ComparisonTableItems).profitOpen"
|
||||
:profit-desc="`Total Profit (Open and realized) ${formatPercent(
|
||||
(item as unknown as ComparisonTableItems).profitOpenRatio ?? 0.0,
|
||||
)}`"
|
||||
:stake-currency="(item as unknown as ComparisonTableItems).stakeCurrency"
|
||||
/>
|
||||
</template>
|
||||
<template #cell(profitClosed)="{ item }">
|
||||
<ProfitPill
|
||||
v-if="item.profitClosed && item.botId != 'Summary'"
|
||||
:profit-ratio="(item as unknown as ComparisonTableItems).profitClosedRatio"
|
||||
:profit-abs="(item as unknown as ComparisonTableItems).profitClosed"
|
||||
:stake-currency="(item as unknown as ComparisonTableItems).stakeCurrency"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #cell(balance)="{ item }">
|
||||
<div v-if="item.balance">
|
||||
<span :title="(item as unknown as ComparisonTableItems).stakeCurrency"
|
||||
>{{
|
||||
formatPrice(
|
||||
(item as unknown as ComparisonTableItems).balance ?? 0,
|
||||
(item as unknown as ComparisonTableItems).stakeCurrencyDecimals,
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span class="text-small">{{
|
||||
` ${item.stakeCurrency}${item.isDryRun ? ' (dry)' : ''}`
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(winVsLoss)="{ item }">
|
||||
<div v-if="item.losses !== undefined">
|
||||
<span class="text-profit">{{ item.wins }}</span> /
|
||||
<span class="text-loss">{{ item.losses }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</BTable>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { ProfitInterface, ComparisonTableItems } from '@/types';
|
||||
|
@ -159,4 +86,77 @@ const tableItems = computed<TableItem[]>(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BTable
|
||||
ref="tradesTable"
|
||||
small
|
||||
hover
|
||||
show-empty
|
||||
primary-key="botId"
|
||||
:items="tableItems"
|
||||
:fields="tableFields"
|
||||
>
|
||||
<template #cell(botName)="{ item, value }">
|
||||
<div class="d-flex flex-row">
|
||||
<BFormCheckbox
|
||||
v-if="item.botId && botStore.botCount > 1"
|
||||
v-model="
|
||||
botStore.botStores[(item as unknown as ComparisonTableItems).botId ?? ''].isSelected
|
||||
"
|
||||
title="Show this bot in Dashboard"
|
||||
>{{ value }}</BFormCheckbox
|
||||
>
|
||||
<BFormCheckbox
|
||||
v-if="!item.botId && botStore.botCount > 1"
|
||||
v-model="allToggled"
|
||||
title="Toggle all bots"
|
||||
>{{ value }}</BFormCheckbox
|
||||
>
|
||||
<span v-if="botStore.botCount <= 1">{{ value }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(profitOpen)="{ item }">
|
||||
<ProfitPill
|
||||
v-if="item.profitOpen && item.botId != 'Summary'"
|
||||
:profit-ratio="(item as unknown as ComparisonTableItems).profitOpenRatio"
|
||||
:profit-abs="(item as unknown as ComparisonTableItems).profitOpen"
|
||||
:profit-desc="`Total Profit (Open and realized) ${formatPercent(
|
||||
(item as unknown as ComparisonTableItems).profitOpenRatio ?? 0.0,
|
||||
)}`"
|
||||
:stake-currency="(item as unknown as ComparisonTableItems).stakeCurrency"
|
||||
/>
|
||||
</template>
|
||||
<template #cell(profitClosed)="{ item }">
|
||||
<ProfitPill
|
||||
v-if="item.profitClosed && item.botId != 'Summary'"
|
||||
:profit-ratio="(item as unknown as ComparisonTableItems).profitClosedRatio"
|
||||
:profit-abs="(item as unknown as ComparisonTableItems).profitClosed"
|
||||
:stake-currency="(item as unknown as ComparisonTableItems).stakeCurrency"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #cell(balance)="{ item }">
|
||||
<div v-if="item.balance">
|
||||
<span :title="(item as unknown as ComparisonTableItems).stakeCurrency"
|
||||
>{{
|
||||
formatPrice(
|
||||
(item as unknown as ComparisonTableItems).balance ?? 0,
|
||||
(item as unknown as ComparisonTableItems).stakeCurrencyDecimals,
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span class="text-small">{{
|
||||
` ${item.stakeCurrency}${item.isDryRun ? ' (dry)' : ''}`
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(winVsLoss)="{ item }">
|
||||
<div v-if="item.losses !== undefined">
|
||||
<span class="text-profit">{{ item.wins }}</span> /
|
||||
<span class="text-loss">{{ item.losses }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</BTable>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,69 +1,4 @@
|
|||
forceexit
|
||||
<template>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || isRunning"
|
||||
title="Start Trading"
|
||||
@click="botStore.activeBot.startBot()"
|
||||
>
|
||||
<i-mdi-play height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || !isRunning"
|
||||
title="Stop Trading - Also stops handling open trades."
|
||||
@click="handleStopBot()"
|
||||
>
|
||||
<i-mdi-stop height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || !isRunning"
|
||||
title="StopBuy - Stops buying, but still handles open trades"
|
||||
@click="handleStopBuy()"
|
||||
>
|
||||
<i-mdi-pause height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading"
|
||||
title="Reload Config - reloads configuration including strategy, resetting all settings changed on the fly."
|
||||
@click="handleReloadConfig()"
|
||||
>
|
||||
<i-mdi-reload height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading"
|
||||
title="Force exit all"
|
||||
@click="handleForceExit()"
|
||||
>
|
||||
<i-mdi-close-box-multiple height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
v-if="botStore.activeBot.botState && botStore.activeBot.botState.force_entry_enable"
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || !isRunning"
|
||||
title="Force enter - Immediately enter a trade at an optional price. Exits are then handled according to strategy rules."
|
||||
@click="forceEnter = true"
|
||||
>
|
||||
<i-mdi-plus-box-multiple-outline style="font-size: 20px" />
|
||||
</button>
|
||||
<button
|
||||
v-if="botStore.activeBot.isWebserverMode && false"
|
||||
:disabled="botStore.activeBot.isTrading"
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
title="Start Trading mode"
|
||||
@click="botStore.activeBot.startTrade()"
|
||||
>
|
||||
<i-mdi-play class="fs-4" />
|
||||
</button>
|
||||
<ForceEntryForm v-model="forceEnter" :pair="botStore.activeBot.selectedPair" />
|
||||
<MessageBox ref="msgBox" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MessageBox, { MsgBoxObject } from '@/components/general/MessageBox.vue';
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
@ -128,3 +63,68 @@ const handleForceExit = () => {
|
|||
msgBox.value?.show(msg);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || isRunning"
|
||||
title="Start Trading"
|
||||
@click="botStore.activeBot.startBot()"
|
||||
>
|
||||
<i-mdi-play height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || !isRunning"
|
||||
title="Stop Trading - Also stops handling open trades."
|
||||
@click="handleStopBot()"
|
||||
>
|
||||
<i-mdi-stop height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || !isRunning"
|
||||
title="StopBuy - Stops buying, but still handles open trades"
|
||||
@click="handleStopBuy()"
|
||||
>
|
||||
<i-mdi-pause height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading"
|
||||
title="Reload Config - reloads configuration including strategy, resetting all settings changed on the fly."
|
||||
@click="handleReloadConfig()"
|
||||
>
|
||||
<i-mdi-reload height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading"
|
||||
title="Force exit all"
|
||||
@click="handleForceExit()"
|
||||
>
|
||||
<i-mdi-close-box-multiple height="24" width="24" />
|
||||
</button>
|
||||
<button
|
||||
v-if="botStore.activeBot.botState && botStore.activeBot.botState.force_entry_enable"
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
:disabled="!botStore.activeBot.isTrading || !isRunning"
|
||||
title="Force enter - Immediately enter a trade at an optional price. Exits are then handled according to strategy rules."
|
||||
@click="forceEnter = true"
|
||||
>
|
||||
<i-mdi-plus-box-multiple-outline style="font-size: 20px" />
|
||||
</button>
|
||||
<button
|
||||
v-if="botStore.activeBot.isWebserverMode && false"
|
||||
:disabled="botStore.activeBot.isTrading"
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
title="Start Trading mode"
|
||||
@click="botStore.activeBot.startTrade()"
|
||||
>
|
||||
<i-mdi-play class="fs-4" />
|
||||
</button>
|
||||
<ForceEntryForm v-model="forceEnter" :pair="botStore.activeBot.selectedPair" />
|
||||
<MessageBox ref="msgBox" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
<template>
|
||||
<BTable class="text-start" small borderless :items="profitItems" :fields="profitFields">
|
||||
<template #cell(value)="row">
|
||||
<DateTimeTZ v-if="row.item.isTs && row.value" :date="row.value as number"></DateTimeTZ>
|
||||
<template v-else>{{ row.value }}</template>
|
||||
</template>
|
||||
</BTable>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ProfitInterface } from '@/types';
|
||||
import { TableField, TableItem } from 'bootstrap-vue-next';
|
||||
|
@ -125,3 +116,12 @@ const profitItems = computed<TableItem[]>(() => {
|
|||
];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BTable class="text-start" small borderless :items="profitItems" :fields="profitFields">
|
||||
<template #cell(value)="row">
|
||||
<DateTimeTZ v-if="row.item.isTs && row.value" :date="row.value as number"></DateTimeTZ>
|
||||
<template v-else>{{ row.value }}</template>
|
||||
</template>
|
||||
</BTable>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="botStore.activeBot.botState">
|
||||
<p>
|
||||
|
@ -84,9 +90,3 @@
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const botStore = useBotStore();
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const props = defineProps({
|
||||
trades: { required: true, type: Array as () => Trade[] },
|
||||
title: { default: 'Trades', type: String },
|
||||
stakeCurrency: { required: false, default: '', type: String },
|
||||
activeTrades: { default: false, type: Boolean },
|
||||
showFilter: { default: false, type: Boolean },
|
||||
multiBotView: { default: false, type: Boolean },
|
||||
emptyText: { default: 'No Trades to show.', type: String },
|
||||
stakeCurrencyDecimals: { default: 3, type: Number },
|
||||
});
|
||||
const botStore = useBotStore();
|
||||
const currentPage = ref(1);
|
||||
const filterText = ref('');
|
||||
const perPage = props.activeTrades ? 200 : 25;
|
||||
|
||||
const rows = computed(() => props.trades.length);
|
||||
|
||||
const filteredTrades = computed(() => {
|
||||
return props.trades.slice((currentPage.value - 1) * perPage, currentPage.value * perPage);
|
||||
});
|
||||
|
||||
const tradeClick = (trade) => {
|
||||
botStore.activeBot.setDetailTrade(trade);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-100 overflow-auto p-1">
|
||||
<BListGroup id="tradeList">
|
||||
|
@ -33,37 +64,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[] },
|
||||
title: { default: 'Trades', type: String },
|
||||
stakeCurrency: { required: false, default: '', type: String },
|
||||
activeTrades: { default: false, type: Boolean },
|
||||
showFilter: { default: false, type: Boolean },
|
||||
multiBotView: { default: false, type: Boolean },
|
||||
emptyText: { default: 'No Trades to show.', type: String },
|
||||
stakeCurrencyDecimals: { default: 3, type: Number },
|
||||
});
|
||||
const botStore = useBotStore();
|
||||
const currentPage = ref(1);
|
||||
const filterText = ref('');
|
||||
const perPage = props.activeTrades ? 200 : 25;
|
||||
|
||||
const rows = computed(() => props.trades.length);
|
||||
|
||||
const filteredTrades = computed(() => {
|
||||
return props.trades.slice((currentPage.value - 1) * perPage, currentPage.value * perPage);
|
||||
});
|
||||
|
||||
const tradeClick = (trade) => {
|
||||
botStore.activeBot.setDetailTrade(trade);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-05 {
|
||||
margin-top: 0.125rem;
|
||||
|
|
|
@ -1,20 +1,3 @@
|
|||
<template>
|
||||
<div class="d-flex">
|
||||
<div
|
||||
class="px-1 d-flex flex-row flex-fill text-start justify-content-between align-items-center"
|
||||
>
|
||||
<span>
|
||||
<span class="me-1 fw-bold">{{ trade.pair }}</span>
|
||||
<small class="text-secondary">(#{{ trade.trade_id }})</small>
|
||||
</span>
|
||||
<small>
|
||||
<DateTimeTZ :date="trade.open_timestamp" :date-only="true" />
|
||||
</small>
|
||||
</div>
|
||||
<TradeProfit class="col-5" :trade="trade" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Trade } from '@/types';
|
||||
import TradeProfit from './TradeProfit.vue';
|
||||
|
@ -35,6 +18,23 @@ defineProps({
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex">
|
||||
<div
|
||||
class="px-1 d-flex flex-row flex-fill text-start justify-content-between align-items-center"
|
||||
>
|
||||
<span>
|
||||
<span class="me-1 fw-bold">{{ trade.pair }}</span>
|
||||
<small class="text-secondary">(#{{ trade.trade_id }})</small>
|
||||
</span>
|
||||
<small>
|
||||
<DateTimeTZ :date="trade.open_timestamp" :date-only="true" />
|
||||
</small>
|
||||
</div>
|
||||
<TradeProfit class="col-5" :trade="trade" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-body {
|
||||
padding: 0 0.2em;
|
||||
|
|
|
@ -1,26 +1,3 @@
|
|||
<template>
|
||||
<div class="w-100 d-flex">
|
||||
<BFormSelect
|
||||
id="exchange-select"
|
||||
v-model="exchangeModel.exchange"
|
||||
size="sm"
|
||||
:options="exchangeList"
|
||||
>
|
||||
</BFormSelect>
|
||||
<BFormSelect
|
||||
id="tradeMode-select"
|
||||
v-model="exchangeModel.trade_mode"
|
||||
size="sm"
|
||||
:options="tradeModes"
|
||||
:disabled="tradeModes.length < 2"
|
||||
>
|
||||
</BFormSelect>
|
||||
<BButton class="ms-2 no-min-w" size="sm" @click="botStore.activeBot.getExchangeList">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
|
@ -78,3 +55,26 @@ onMounted(() => {
|
|||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-100 d-flex">
|
||||
<BFormSelect
|
||||
id="exchange-select"
|
||||
v-model="exchangeModel.exchange"
|
||||
size="sm"
|
||||
:options="exchangeList"
|
||||
>
|
||||
</BFormSelect>
|
||||
<BFormSelect
|
||||
id="tradeMode-select"
|
||||
v-model="exchangeModel.trade_mode"
|
||||
size="sm"
|
||||
:options="tradeModes"
|
||||
:disabled="tradeModes.length < 2"
|
||||
>
|
||||
</BFormSelect>
|
||||
<BButton class="ms-2 no-min-w" size="sm" @click="botStore.activeBot.getExchangeList">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,92 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { ForceEnterPayload, OrderSides } from '@/types';
|
||||
|
||||
const props = defineProps({
|
||||
pair: { type: String, default: '' },
|
||||
positionIncrease: { type: Boolean, default: false },
|
||||
});
|
||||
const model = defineModel<boolean>();
|
||||
const botStore = useBotStore();
|
||||
|
||||
const form = ref<HTMLFormElement>();
|
||||
const selectedPair = ref('');
|
||||
const price = ref<number | undefined>(undefined);
|
||||
const stakeAmount = ref<number | undefined>(undefined);
|
||||
const leverage = ref<number | undefined>(undefined);
|
||||
|
||||
const ordertype = ref('');
|
||||
const orderSide = ref<OrderSides>(OrderSides.long);
|
||||
const enterTag = ref('force_entry');
|
||||
|
||||
const orderTypeOptions = [
|
||||
{ value: 'market', text: 'Market' },
|
||||
{ value: 'limit', text: 'Limit' },
|
||||
];
|
||||
const orderSideOptions = [
|
||||
{ value: 'long', text: 'Long' },
|
||||
{ value: 'short', text: 'Short' },
|
||||
];
|
||||
|
||||
const checkFormValidity = () => {
|
||||
const valid = form.value?.checkValidity();
|
||||
|
||||
return valid;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// Exit when the form isn't valid
|
||||
if (!checkFormValidity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// call forceentry
|
||||
const payload: ForceEnterPayload = { pair: selectedPair.value };
|
||||
if (price.value) {
|
||||
payload.price = Number(price.value);
|
||||
}
|
||||
if (ordertype.value) {
|
||||
payload.ordertype = ordertype.value;
|
||||
}
|
||||
if (stakeAmount.value) {
|
||||
payload.stakeamount = stakeAmount.value;
|
||||
}
|
||||
if (botStore.activeBot.botApiVersion >= 2.13 && botStore.activeBot.shortAllowed) {
|
||||
payload.side = orderSide.value;
|
||||
}
|
||||
if (botStore.activeBot.botApiVersion >= 2.16 && enterTag.value) {
|
||||
payload.entry_tag = enterTag.value;
|
||||
}
|
||||
|
||||
if (leverage.value) {
|
||||
payload.leverage = leverage.value;
|
||||
}
|
||||
botStore.activeBot.forceentry(payload);
|
||||
await nextTick();
|
||||
model.value = false;
|
||||
};
|
||||
const resetForm = () => {
|
||||
console.log('resetForm');
|
||||
selectedPair.value = props.pair;
|
||||
price.value = undefined;
|
||||
stakeAmount.value = undefined;
|
||||
ordertype.value =
|
||||
botStore.activeBot.botState?.order_types?.forcebuy ||
|
||||
botStore.activeBot.botState?.order_types?.force_entry ||
|
||||
botStore.activeBot.botState?.order_types?.buy ||
|
||||
botStore.activeBot.botState?.order_types?.entry ||
|
||||
'limit';
|
||||
};
|
||||
|
||||
const handleEntry = () => {
|
||||
// Trigger submit handler
|
||||
handleSubmit();
|
||||
};
|
||||
const inputSelect = (bvModalEvt) => {
|
||||
bvModalEvt.srcElement?.select();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BModal
|
||||
id="forceentry-modal"
|
||||
|
@ -117,92 +206,3 @@
|
|||
</form>
|
||||
</BModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { ForceEnterPayload, OrderSides } from '@/types';
|
||||
|
||||
const props = defineProps({
|
||||
pair: { type: String, default: '' },
|
||||
positionIncrease: { type: Boolean, default: false },
|
||||
});
|
||||
const model = defineModel<boolean>();
|
||||
const botStore = useBotStore();
|
||||
|
||||
const form = ref<HTMLFormElement>();
|
||||
const selectedPair = ref('');
|
||||
const price = ref<number | undefined>(undefined);
|
||||
const stakeAmount = ref<number | undefined>(undefined);
|
||||
const leverage = ref<number | undefined>(undefined);
|
||||
|
||||
const ordertype = ref('');
|
||||
const orderSide = ref<OrderSides>(OrderSides.long);
|
||||
const enterTag = ref('force_entry');
|
||||
|
||||
const orderTypeOptions = [
|
||||
{ value: 'market', text: 'Market' },
|
||||
{ value: 'limit', text: 'Limit' },
|
||||
];
|
||||
const orderSideOptions = [
|
||||
{ value: 'long', text: 'Long' },
|
||||
{ value: 'short', text: 'Short' },
|
||||
];
|
||||
|
||||
const checkFormValidity = () => {
|
||||
const valid = form.value?.checkValidity();
|
||||
|
||||
return valid;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// Exit when the form isn't valid
|
||||
if (!checkFormValidity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// call forceentry
|
||||
const payload: ForceEnterPayload = { pair: selectedPair.value };
|
||||
if (price.value) {
|
||||
payload.price = Number(price.value);
|
||||
}
|
||||
if (ordertype.value) {
|
||||
payload.ordertype = ordertype.value;
|
||||
}
|
||||
if (stakeAmount.value) {
|
||||
payload.stakeamount = stakeAmount.value;
|
||||
}
|
||||
if (botStore.activeBot.botApiVersion >= 2.13 && botStore.activeBot.shortAllowed) {
|
||||
payload.side = orderSide.value;
|
||||
}
|
||||
if (botStore.activeBot.botApiVersion >= 2.16 && enterTag.value) {
|
||||
payload.entry_tag = enterTag.value;
|
||||
}
|
||||
|
||||
if (leverage.value) {
|
||||
payload.leverage = leverage.value;
|
||||
}
|
||||
botStore.activeBot.forceentry(payload);
|
||||
await nextTick();
|
||||
model.value = false;
|
||||
};
|
||||
const resetForm = () => {
|
||||
console.log('resetForm');
|
||||
selectedPair.value = props.pair;
|
||||
price.value = undefined;
|
||||
stakeAmount.value = undefined;
|
||||
ordertype.value =
|
||||
botStore.activeBot.botState?.order_types?.forcebuy ||
|
||||
botStore.activeBot.botState?.order_types?.force_entry ||
|
||||
botStore.activeBot.botState?.order_types?.buy ||
|
||||
botStore.activeBot.botState?.order_types?.entry ||
|
||||
'limit';
|
||||
};
|
||||
|
||||
const handleEntry = () => {
|
||||
// Trigger submit handler
|
||||
handleSubmit();
|
||||
};
|
||||
const inputSelect = (bvModalEvt) => {
|
||||
bvModalEvt.srcElement?.select();
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,58 +1,3 @@
|
|||
<template>
|
||||
<div>
|
||||
<BModal
|
||||
id="forceexit-modal"
|
||||
v-model="model"
|
||||
title="Force exiting a trade"
|
||||
@show="resetForm"
|
||||
@hidden="resetForm"
|
||||
@ok="handleEntry"
|
||||
>
|
||||
<form ref="form" @submit.stop.prevent="handleSubmit">
|
||||
<p>
|
||||
<span>Exiting Trade #{{ trade.trade_id }} {{ trade.pair }}.</span>
|
||||
<br />
|
||||
<span>Currently owning {{ trade.amount }} {{ trade.base_currency }}</span>
|
||||
</p>
|
||||
<BFormGroup
|
||||
label-for="stake-input"
|
||||
invalid-feedback="Amount must be empty or a positive number"
|
||||
:state="amount !== undefined && amount > 0"
|
||||
>
|
||||
<template #label>
|
||||
<span class="fst-italic">*Amount in {{ trade.base_currency }} [optional]</span>
|
||||
<span class="ms-1 fst-italic">{{ amountInBase }}</span>
|
||||
</template>
|
||||
<BFormInput id="stake-input" v-model="amount" type="number" step="0.000001"></BFormInput>
|
||||
<BFormInput
|
||||
id="stake-input"
|
||||
v-model="amount"
|
||||
type="range"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
:max="trade.amount"
|
||||
></BFormInput>
|
||||
</BFormGroup>
|
||||
|
||||
<BFormGroup
|
||||
label="*OrderType"
|
||||
label-for="ordertype-input"
|
||||
invalid-feedback="OrderType"
|
||||
:state="ordertype !== undefined"
|
||||
>
|
||||
<BFormSelect
|
||||
v-model="ordertype"
|
||||
:options="['market', 'limit']"
|
||||
style="min-width: 7em"
|
||||
size="sm"
|
||||
>
|
||||
</BFormSelect>
|
||||
</BFormGroup>
|
||||
</form>
|
||||
</BModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { ForceSellPayload, Trade } from '@/types';
|
||||
|
@ -121,3 +66,58 @@ const amountInBase = computed<string>(() => {
|
|||
: '';
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<BModal
|
||||
id="forceexit-modal"
|
||||
v-model="model"
|
||||
title="Force exiting a trade"
|
||||
@show="resetForm"
|
||||
@hidden="resetForm"
|
||||
@ok="handleEntry"
|
||||
>
|
||||
<form ref="form" @submit.stop.prevent="handleSubmit">
|
||||
<p>
|
||||
<span>Exiting Trade #{{ trade.trade_id }} {{ trade.pair }}.</span>
|
||||
<br />
|
||||
<span>Currently owning {{ trade.amount }} {{ trade.base_currency }}</span>
|
||||
</p>
|
||||
<BFormGroup
|
||||
label-for="stake-input"
|
||||
invalid-feedback="Amount must be empty or a positive number"
|
||||
:state="amount !== undefined && amount > 0"
|
||||
>
|
||||
<template #label>
|
||||
<span class="fst-italic">*Amount in {{ trade.base_currency }} [optional]</span>
|
||||
<span class="ms-1 fst-italic">{{ amountInBase }}</span>
|
||||
</template>
|
||||
<BFormInput id="stake-input" v-model="amount" type="number" step="0.000001"></BFormInput>
|
||||
<BFormInput
|
||||
id="stake-input"
|
||||
v-model="amount"
|
||||
type="range"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
:max="trade.amount"
|
||||
></BFormInput>
|
||||
</BFormGroup>
|
||||
|
||||
<BFormGroup
|
||||
label="*OrderType"
|
||||
label-for="ordertype-input"
|
||||
invalid-feedback="OrderType"
|
||||
:state="ordertype !== undefined"
|
||||
>
|
||||
<BFormSelect
|
||||
v-model="ordertype"
|
||||
:options="['market', 'limit']"
|
||||
style="min-width: 7em"
|
||||
size="sm"
|
||||
>
|
||||
</BFormSelect>
|
||||
</BFormGroup>
|
||||
</form>
|
||||
</BModal>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const locFreqaiModel = defineModel<string>();
|
||||
const botStore = useBotStore();
|
||||
|
||||
onMounted(() => {
|
||||
if (botStore.activeBot.freqaiModelList.length === 0) {
|
||||
botStore.activeBot.getFreqAIModelList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="w-100 d-flex">
|
||||
|
@ -15,16 +28,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const locFreqaiModel = defineModel<string>();
|
||||
const botStore = useBotStore();
|
||||
|
||||
onMounted(() => {
|
||||
if (botStore.activeBot.freqaiModelList.length === 0) {
|
||||
botStore.activeBot.getFreqAIModelList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,25 +1,3 @@
|
|||
<template>
|
||||
<div class="d-flex h-100 p-0 align-items-start">
|
||||
<div ref="scrollContainer" class="border p-1 text-start pb-5 w-100 h-100 overflow-auto">
|
||||
<pre
|
||||
v-for="(log, index) in botStore.activeBot.lastLogs"
|
||||
:key="index"
|
||||
class="m-0 overflow-visible"
|
||||
style="line-height: unset"
|
||||
><span class="text-muted">{{ log[0] }} <span :class="getLogColor(log[3])">{{ log[3].padEnd(7, ' ') }}</span> {{ log[2] }} - </span><span class="text-{{ log[1] }}">{{ log[4] }}</span
|
||||
></pre>
|
||||
</div>
|
||||
<div class="d-flex flex-column gap-1 ms-1">
|
||||
<BButton id="refresh-logs" size="sm" title="Reload Logs" @click="refreshLogs">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
<BButton size="sm" title="Scroll to bottom" @click="scrollToBottom">
|
||||
<i-mdi-arrow-down-thick />
|
||||
</BButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
|
@ -53,6 +31,28 @@ function scrollToBottom() {
|
|||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex h-100 p-0 align-items-start">
|
||||
<div ref="scrollContainer" class="border p-1 text-start pb-5 w-100 h-100 overflow-auto">
|
||||
<pre
|
||||
v-for="(log, index) in botStore.activeBot.lastLogs"
|
||||
:key="index"
|
||||
class="m-0 overflow-visible"
|
||||
style="line-height: unset"
|
||||
><span class="text-muted">{{ log[0] }} <span :class="getLogColor(log[3])">{{ log[3].padEnd(7, ' ') }}</span> {{ log[2] }} - </span><span class="text-{{ log[1] }}">{{ log[4] }}</span
|
||||
></pre>
|
||||
</div>
|
||||
<div class="d-flex flex-column gap-1 ms-1">
|
||||
<BButton id="refresh-logs" size="sm" title="Reload Logs" @click="refreshLogs">
|
||||
<i-mdi-refresh />
|
||||
</BButton>
|
||||
<BButton size="sm" title="Scroll to bottom" @click="scrollToBottom">
|
||||
<i-mdi-arrow-down-thick />
|
||||
</BButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
textarea {
|
||||
width: 100%;
|
||||
|
|
|
@ -1,3 +1,56 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const newblacklistpair = ref('');
|
||||
const blackListShow = ref(false);
|
||||
const blacklistSelect = ref<number[]>([]);
|
||||
const botStore = useBotStore();
|
||||
|
||||
const initBlacklist = () => {
|
||||
if (botStore.activeBot.whitelist.length === 0) {
|
||||
botStore.activeBot.getWhitelist();
|
||||
}
|
||||
if (botStore.activeBot.blacklist.length === 0) {
|
||||
botStore.activeBot.getBlacklist();
|
||||
}
|
||||
};
|
||||
|
||||
const addBlacklistPair = () => {
|
||||
if (newblacklistpair.value) {
|
||||
blackListShow.value = false;
|
||||
|
||||
botStore.activeBot.addBlacklist({ blacklist: [newblacklistpair.value] });
|
||||
newblacklistpair.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
const blacklistSelectClick = (key) => {
|
||||
const index = blacklistSelect.value.indexOf(key);
|
||||
if (index > -1) {
|
||||
blacklistSelect.value.splice(index, 1);
|
||||
} else {
|
||||
blacklistSelect.value.push(key);
|
||||
}
|
||||
};
|
||||
|
||||
const deletePairs = () => {
|
||||
if (blacklistSelect.value.length === 0) {
|
||||
console.log('nothing to delete');
|
||||
return;
|
||||
}
|
||||
// const pairlist = blacklistSelect.value;
|
||||
const pairlist = botStore.activeBot.blacklist.filter(
|
||||
(value, index) => blacklistSelect.value.indexOf(index) > -1,
|
||||
);
|
||||
console.log('Deleting pairs: ', pairlist);
|
||||
botStore.activeBot.deleteBlacklist(pairlist);
|
||||
blacklistSelect.value = [];
|
||||
};
|
||||
onMounted(() => {
|
||||
initBlacklist();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
|
@ -94,59 +147,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
|
||||
const newblacklistpair = ref('');
|
||||
const blackListShow = ref(false);
|
||||
const blacklistSelect = ref<number[]>([]);
|
||||
const botStore = useBotStore();
|
||||
|
||||
const initBlacklist = () => {
|
||||
if (botStore.activeBot.whitelist.length === 0) {
|
||||
botStore.activeBot.getWhitelist();
|
||||
}
|
||||
if (botStore.activeBot.blacklist.length === 0) {
|
||||
botStore.activeBot.getBlacklist();
|
||||
}
|
||||
};
|
||||
|
||||
const addBlacklistPair = () => {
|
||||
if (newblacklistpair.value) {
|
||||
blackListShow.value = false;
|
||||
|
||||
botStore.activeBot.addBlacklist({ blacklist: [newblacklistpair.value] });
|
||||
newblacklistpair.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
const blacklistSelectClick = (key) => {
|
||||
const index = blacklistSelect.value.indexOf(key);
|
||||
if (index > -1) {
|
||||
blacklistSelect.value.splice(index, 1);
|
||||
} else {
|
||||
blacklistSelect.value.push(key);
|
||||
}
|
||||
};
|
||||
|
||||
const deletePairs = () => {
|
||||
if (blacklistSelect.value.length === 0) {
|
||||
console.log('nothing to delete');
|
||||
return;
|
||||
}
|
||||
// const pairlist = blacklistSelect.value;
|
||||
const pairlist = botStore.activeBot.blacklist.filter(
|
||||
(value, index) => blacklistSelect.value.indexOf(index) > -1,
|
||||
);
|
||||
console.log('Deleting pairs: ', pairlist);
|
||||
botStore.activeBot.deleteBlacklist(pairlist);
|
||||
blacklistSelect.value = [];
|
||||
};
|
||||
onMounted(() => {
|
||||
initBlacklist();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.check {
|
||||
// Hidden checkbox on blacklist selection
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
<script setup lang="ts">
|
||||
import { Lock } from '@/types';
|
||||
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { TableField } from 'bootstrap-vue-next';
|
||||
const botStore = useBotStore();
|
||||
|
||||
const tableFields: TableField[] = [
|
||||
{ key: 'pair', label: 'Pair' },
|
||||
{ key: 'lock_end_timestamp', label: 'Until', formatter: (value) => timestampms(value as number) },
|
||||
{ key: 'reason', label: 'Reason' },
|
||||
{ key: 'actions' },
|
||||
];
|
||||
|
||||
const removePairLock = (item: Lock) => {
|
||||
console.log(item);
|
||||
if (item.id !== undefined) {
|
||||
botStore.activeBot.deleteLock(item.id);
|
||||
} else {
|
||||
showAlert('This Freqtrade version does not support deleting locks.');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
|
@ -23,28 +47,4 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Lock } from '@/types';
|
||||
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { TableField } from 'bootstrap-vue-next';
|
||||
const botStore = useBotStore();
|
||||
|
||||
const tableFields: TableField[] = [
|
||||
{ key: 'pair', label: 'Pair' },
|
||||
{ key: 'lock_end_timestamp', label: 'Until', formatter: (value) => timestampms(value as number) },
|
||||
{ key: 'reason', label: 'Reason' },
|
||||
{ key: 'actions' },
|
||||
];
|
||||
|
||||
const removePairLock = (item: Lock) => {
|
||||
console.log(item);
|
||||
if (item.id !== undefined) {
|
||||
botStore.activeBot.deleteLock(item.id);
|
||||
} else {
|
||||
showAlert('This Freqtrade version does not support deleting locks.');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,41 +1,3 @@
|
|||
<template>
|
||||
<div>
|
||||
<BFormGroup
|
||||
label-for="trade-filter"
|
||||
class="mb-2 ms-2"
|
||||
:class="{
|
||||
'me-4': backtestMode,
|
||||
'me-2': !backtestMode,
|
||||
}"
|
||||
>
|
||||
<BFormInput id="trade-filter" v-model="filterText" type="text" placeholder="Filter" />
|
||||
</BFormGroup>
|
||||
<BListGroup>
|
||||
<BListGroupItem
|
||||
v-for="comb in combinedPairList"
|
||||
:key="comb.pair"
|
||||
button
|
||||
class="d-flex justify-content-between align-items-center py-1"
|
||||
:active="comb.pair === botStore.activeBot.selectedPair"
|
||||
:title="`${comb.pair} - ${comb.tradeCount} trades`"
|
||||
@click="botStore.activeBot.selectedPair = comb.pair"
|
||||
>
|
||||
<div>
|
||||
{{ comb.pair }}
|
||||
<span v-if="comb.locks" :title="comb.lockReason"> <i-mdi-lock /> </span>
|
||||
</div>
|
||||
|
||||
<TradeProfit v-if="comb.trade && !backtestMode" :trade="comb.trade" />
|
||||
<ProfitPill
|
||||
v-if="backtestMode && comb.tradeCount > 0"
|
||||
:profit-ratio="comb.profit"
|
||||
:stake-currency="botStore.activeBot.stakeCurrency"
|
||||
/>
|
||||
</BListGroupItem>
|
||||
</BListGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Lock, Trade } from '@/types';
|
||||
|
||||
|
@ -131,6 +93,44 @@ const combinedPairList = computed(() => {
|
|||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<BFormGroup
|
||||
label-for="trade-filter"
|
||||
class="mb-2 ms-2"
|
||||
:class="{
|
||||
'me-4': backtestMode,
|
||||
'me-2': !backtestMode,
|
||||
}"
|
||||
>
|
||||
<BFormInput id="trade-filter" v-model="filterText" type="text" placeholder="Filter" />
|
||||
</BFormGroup>
|
||||
<BListGroup>
|
||||
<BListGroupItem
|
||||
v-for="comb in combinedPairList"
|
||||
:key="comb.pair"
|
||||
button
|
||||
class="d-flex justify-content-between align-items-center py-1"
|
||||
:active="comb.pair === botStore.activeBot.selectedPair"
|
||||
:title="`${comb.pair} - ${comb.tradeCount} trades`"
|
||||
@click="botStore.activeBot.selectedPair = comb.pair"
|
||||
>
|
||||
<div>
|
||||
{{ comb.pair }}
|
||||
<span v-if="comb.locks" :title="comb.lockReason"> <i-mdi-lock /> </span>
|
||||
</div>
|
||||
|
||||
<TradeProfit v-if="comb.trade && !backtestMode" :trade="comb.trade" />
|
||||
<ProfitPill
|
||||
v-if="backtestMode && comb.tradeCount > 0"
|
||||
:profit-ratio="comb.profit"
|
||||
:stake-currency="botStore.activeBot.stakeCurrency"
|
||||
/>
|
||||
</BListGroupItem>
|
||||
</BListGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.list-group {
|
||||
text-align: left;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import EditValue from '../general/EditValue.vue';
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
</script>
|
||||
<template>
|
||||
<div class="d-flex flex-column flex-sm-row mb-2 gap-2">
|
||||
<BButton
|
||||
|
@ -40,8 +45,3 @@
|
|||
</BButton>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import EditValue from '../general/EditValue.vue';
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
const copyFromConfig = ref('');
|
||||
const visible = ref(false);
|
||||
|
||||
const configNames = computed(() =>
|
||||
pairlistStore.savedConfigs.filter((c) => c.name !== pairlistStore.config.name).map((c) => c.name),
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<BCard no-body class="mb-2">
|
||||
<template #header>
|
||||
|
@ -48,14 +58,4 @@
|
|||
</BCollapse>
|
||||
</BCard>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
const copyFromConfig = ref('');
|
||||
const visible = ref(false);
|
||||
|
||||
const configNames = computed(() =>
|
||||
pairlistStore.savedConfigs.filter((c) => c.name !== pairlistStore.config.name).map((c) => c.name),
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import { Pairlist } from '@/types';
|
||||
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
|
||||
defineProps<{
|
||||
index: number;
|
||||
}>();
|
||||
|
||||
const pairlist = defineModel<Pairlist>({ required: true });
|
||||
|
||||
const hasParameters = computed(() => Object.keys(pairlist.value.params).length > 0);
|
||||
|
||||
function toggleVisible() {
|
||||
if (hasParameters.value) {
|
||||
pairlist.value.showParameters = !pairlist.value.showParameters;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BCard no-body class="mb-2">
|
||||
<template #header>
|
||||
|
@ -54,25 +75,4 @@
|
|||
</BCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import { Pairlist } from '@/types';
|
||||
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
|
||||
defineProps<{
|
||||
index: number;
|
||||
}>();
|
||||
|
||||
const pairlist = defineModel<Pairlist>({ required: true });
|
||||
|
||||
const hasParameters = computed(() => Object.keys(pairlist.value.params).length > 0);
|
||||
|
||||
function toggleVisible() {
|
||||
if (hasParameters.value) {
|
||||
pairlist.value.showParameters = !pairlist.value.showParameters;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { PairlistParameter, PairlistParamType } from '@/types';
|
||||
|
||||
defineProps<{
|
||||
param: PairlistParameter;
|
||||
}>();
|
||||
|
||||
// TODO: type should really be PairlistParamValue
|
||||
const paramValue = defineModel<any>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BFormGroup label-cols="4" label-size="md" class="pb-1 text-start" :description="param.help">
|
||||
<BFormInput
|
||||
|
@ -22,14 +33,3 @@
|
|||
</template>
|
||||
</BFormGroup>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PairlistParameter, PairlistParamType } from '@/types';
|
||||
|
||||
defineProps<{
|
||||
param: PairlistParameter;
|
||||
}>();
|
||||
|
||||
// TODO: type should really be PairlistParamValue
|
||||
const paramValue = defineModel<any>();
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import ChartView from '@/views/ChartsView.vue';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
|
||||
const whitelist = ref<{ enabled: boolean; pair: string }[]>([]);
|
||||
|
||||
watch(
|
||||
() => pairlistStore.whitelist,
|
||||
() => {
|
||||
whitelist.value = pairlistStore.whitelist.map((p) => {
|
||||
return {
|
||||
enabled: true,
|
||||
pair: p,
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="whitelist.length > 0" class="d-flex flex-column flex-lg-row px-2">
|
||||
|
@ -38,26 +61,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import ChartView from '@/views/ChartsView.vue';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
|
||||
const whitelist = ref<{ enabled: boolean; pair: string }[]>([]);
|
||||
|
||||
watch(
|
||||
() => pairlistStore.whitelist,
|
||||
() => {
|
||||
whitelist.value = pairlistStore.whitelist.map((p) => {
|
||||
return {
|
||||
enabled: true,
|
||||
pair: p,
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,74 @@
|
|||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import PairlistConfigItem from './PairlistConfigItem.vue';
|
||||
import PairlistConfigBlacklist from './PairlistConfigBlacklist.vue';
|
||||
import PairlistConfigActions from './PairlistConfigActions.vue';
|
||||
import { Pairlist } from '@/types';
|
||||
import { useSortable, moveArrayElement } from '@vueuse/integrations/useSortable';
|
||||
import ExchangeSelect from './ExchangeSelect.vue';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
|
||||
const availablePairlists = ref<Pairlist[]>([]);
|
||||
const pairlistConfigsEl = ref<HTMLElement | null>(null);
|
||||
const availablePairlistsEl = ref<HTMLElement | null>(null);
|
||||
const selectedView = ref<'Config' | 'Results'>('Config');
|
||||
|
||||
const configEmpty = computed(() => {
|
||||
return pairlistStore.config.pairlists.length == 0;
|
||||
});
|
||||
|
||||
useSortable(availablePairlistsEl, availablePairlists.value, {
|
||||
group: {
|
||||
name: 'configurator',
|
||||
pull: 'clone',
|
||||
put: false,
|
||||
},
|
||||
sort: false,
|
||||
filter: '.no-drag',
|
||||
dragClass: 'dragging',
|
||||
});
|
||||
|
||||
useSortable(pairlistConfigsEl, pairlistStore.config.pairlists, {
|
||||
handle: '.handle',
|
||||
group: 'configurator',
|
||||
onUpdate: async (e) => {
|
||||
moveArrayElement(pairlistStore.config.pairlists, e.oldIndex, e.newIndex);
|
||||
},
|
||||
onAdd: (e) => {
|
||||
const pairlist = availablePairlists.value[e.oldIndex];
|
||||
pairlistStore.addToConfig(pairlist, e.newIndex);
|
||||
// quick fix from: https://github.com/SortableJS/Sortable/issues/1515
|
||||
e.clone.replaceWith(e.item);
|
||||
e.clone.remove();
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
availablePairlists.value = (await botStore.activeBot.getPairlists()).pairlists.sort((a, b) =>
|
||||
// Sort by is_pairlist_generator (by name), then by name.
|
||||
// TODO: this might need to be improved
|
||||
a.is_pairlist_generator === b.is_pairlist_generator
|
||||
? a.name.localeCompare(b.name)
|
||||
: a.is_pairlist_generator
|
||||
? -1
|
||||
: 1,
|
||||
);
|
||||
pairlistStore.selectOrCreateConfig(
|
||||
pairlistStore.isSavedConfig(pairlistStore.configName) ? pairlistStore.configName : 'default',
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => pairlistStore.whitelist,
|
||||
() => {
|
||||
selectedView.value = 'Results';
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex px-3 mb-3 gap-3 flex-column flex-lg-row">
|
||||
<BListGroup ref="availablePairlistsEl" class="available-pairlists">
|
||||
|
@ -90,77 +161,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBotStore } from '@/stores/ftbotwrapper';
|
||||
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
|
||||
import PairlistConfigItem from './PairlistConfigItem.vue';
|
||||
import PairlistConfigBlacklist from './PairlistConfigBlacklist.vue';
|
||||
import PairlistConfigActions from './PairlistConfigActions.vue';
|
||||
import { Pairlist } from '@/types';
|
||||
import { useSortable, moveArrayElement } from '@vueuse/integrations/useSortable';
|
||||
import ExchangeSelect from './ExchangeSelect.vue';
|
||||
|
||||
const botStore = useBotStore();
|
||||
const pairlistStore = usePairlistConfigStore();
|
||||
|
||||
const availablePairlists = ref<Pairlist[]>([]);
|
||||
const pairlistConfigsEl = ref<HTMLElement | null>(null);
|
||||
const availablePairlistsEl = ref<HTMLElement | null>(null);
|
||||
const selectedView = ref<'Config' | 'Results'>('Config');
|
||||
|
||||
const configEmpty = computed(() => {
|
||||
return pairlistStore.config.pairlists.length == 0;
|
||||
});
|
||||
|
||||
useSortable(availablePairlistsEl, availablePairlists.value, {
|
||||
group: {
|
||||
name: 'configurator',
|
||||
pull: 'clone',
|
||||
put: false,
|
||||
},
|
||||
sort: false,
|
||||
filter: '.no-drag',
|
||||
dragClass: 'dragging',
|
||||
});
|
||||
|
||||
useSortable(pairlistConfigsEl, pairlistStore.config.pairlists, {
|
||||
handle: '.handle',
|
||||
group: 'configurator',
|
||||
onUpdate: async (e) => {
|
||||
moveArrayElement(pairlistStore.config.pairlists, e.oldIndex, e.newIndex);
|
||||
},
|
||||
onAdd: (e) => {
|
||||
const pairlist = availablePairlists.value[e.oldIndex];
|
||||
pairlistStore.addToConfig(pairlist, e.newIndex);
|
||||
// quick fix from: https://github.com/SortableJS/Sortable/issues/1515
|
||||
e.clone.replaceWith(e.item);
|
||||
e.clone.remove();
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
availablePairlists.value = (await botStore.activeBot.getPairlists()).pairlists.sort((a, b) =>
|
||||
// Sort by is_pairlist_generator (by name), then by name.
|
||||
// TODO: this might need to be improved
|
||||
a.is_pairlist_generator === b.is_pairlist_generator
|
||||
? a.name.localeCompare(b.name)
|
||||
: a.is_pairlist_generator
|
||||
? -1
|
||||
: 1,
|
||||
);
|
||||
pairlistStore.selectOrCreateConfig(
|
||||
pairlistStore.isSavedConfig(pairlistStore.configName) ? pairlistStore.configName : 'default',
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => pairlistStore.whitelist,
|
||||
() => {
|
||||
selectedView.value = 'Results';
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pairlist {
|
||||
&:hover {
|
||||
|
|
Loading…
Reference in New Issue
Block a user