mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-23 03:25:15 +00:00
Merge branch 'main' into pr/Tako88/1265
This commit is contained in:
commit
af05f9fc88
34
index.html
34
index.html
|
@ -1,18 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<title>FreqUI</title>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<title>FreqUI</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body data-bs-theme="dark">
|
||||
<noscript>
|
||||
<strong>We're sorry but FreqUI doesn't work properly without JavaScript enabled. Please enable it to
|
||||
continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but FreqUI doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useColorMode } from 'bootstrap-vue-next';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const mode = useColorMode();
|
||||
|
||||
const activeTheme = ref('');
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
|
@ -18,17 +21,14 @@ const setTheme = (themeName: string) => {
|
|||
}
|
||||
if (themeName.toLowerCase() === 'bootstrap' || themeName.toLowerCase() === 'bootstrap_dark') {
|
||||
// const styles = document.getElementsByTagName('style');
|
||||
document.documentElement.setAttribute(
|
||||
'data-theme',
|
||||
themeName.toLowerCase() === 'bootstrap' ? 'light' : 'dark',
|
||||
);
|
||||
if (activeTheme.value) {
|
||||
// Only transition if simple mode is active
|
||||
document.documentElement.classList.add('ft-theme-transition');
|
||||
document.body.classList.add('ft-theme-transition');
|
||||
window.setTimeout(() => {
|
||||
document.documentElement.classList.remove('ft-theme-transition');
|
||||
document.body.classList.remove('ft-theme-transition');
|
||||
}, 1000);
|
||||
}
|
||||
mode.value = themeName.toLowerCase() === 'bootstrap' ? 'light' : 'dark';
|
||||
}
|
||||
// Save the theme as localstorage
|
||||
settingsStore.currentTheme = themeName;
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
v-model="plotStore.plotConfigName"
|
||||
:allow-edit="allowEdit"
|
||||
:allow-add="allowEdit"
|
||||
:allow-duplicate="allowEdit"
|
||||
editable-name="plot configuration"
|
||||
@rename="plotStore.renamePlotConfig"
|
||||
@delete="plotStore.deletePlotConfig"
|
||||
@new="plotStore.newPlotConfig"
|
||||
@duplicate="plotStore.duplicatePlotConfig"
|
||||
>
|
||||
<b-form-select
|
||||
v-model="plotStore.plotConfigName"
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
<template>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="flex-grow-1">
|
||||
<slot v-if="!editing"> </slot>
|
||||
<slot v-if="mode === EditState.None"> </slot>
|
||||
<b-form-input v-else v-model="localName" size="sm"> </b-form-input>
|
||||
</div>
|
||||
<div
|
||||
class="flex-grow-2 mt-auto d-flex gap-1 ms-1"
|
||||
:class="alignVertical ? 'flex-column' : 'flex-row'"
|
||||
>
|
||||
<template v-if="allowEdit && !(addNew || editing)">
|
||||
<template v-if="allowEdit && mode === EditState.None">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Edit this ${editableName}.`"
|
||||
@click="editing = true"
|
||||
@click="mode = EditState.Editing"
|
||||
>
|
||||
<i-mdi-pencil />
|
||||
</b-button>
|
||||
<b-button
|
||||
v-if="allowDuplicate"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:title="`Duplicate ${editableName}.`"
|
||||
@click="duplicate"
|
||||
>
|
||||
<i-mdi-content-copy />
|
||||
</b-button>
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
|
@ -27,14 +36,14 @@
|
|||
</b-button>
|
||||
</template>
|
||||
<b-button
|
||||
v-if="allowAdd && !(addNew || editing)"
|
||||
v-if="allowAdd && mode === EditState.None"
|
||||
size="sm"
|
||||
:title="`Add new ${editableName}.`"
|
||||
variant="primary"
|
||||
@click="addNewClick"
|
||||
><i-mdi-plus-box-outline />
|
||||
</b-button>
|
||||
<template v-if="addNew || editing">
|
||||
<template v-if="mode !== EditState.None">
|
||||
<b-button
|
||||
size="sm"
|
||||
:title="`Add new '${editableName}`"
|
||||
|
@ -67,6 +76,10 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
allowDuplicate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
editableName: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -78,26 +91,37 @@ const props = defineProps({
|
|||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'delete', value: string): void;
|
||||
(e: 'new', value: string): void;
|
||||
(e: 'rename', oldName: string, newName: string): void;
|
||||
delete: [value: string];
|
||||
new: [value: string];
|
||||
duplicate: [oldName: string, newName: string];
|
||||
rename: [oldName: string, newName: string];
|
||||
}>();
|
||||
|
||||
const addNew = ref(false);
|
||||
enum EditState {
|
||||
None,
|
||||
Editing,
|
||||
Adding,
|
||||
Duplicating,
|
||||
}
|
||||
|
||||
const localName = ref<string>(props.modelValue);
|
||||
const editing = ref<boolean>(false);
|
||||
const mode = ref<EditState>(EditState.None);
|
||||
|
||||
function abort() {
|
||||
editing.value = false;
|
||||
addNew.value = false;
|
||||
mode.value = EditState.None;
|
||||
localName.value = props.modelValue;
|
||||
}
|
||||
|
||||
function duplicate() {
|
||||
localName.value = localName.value + ' (copy)';
|
||||
mode.value = EditState.Duplicating;
|
||||
}
|
||||
|
||||
function addNewClick() {
|
||||
localName.value = '';
|
||||
addNew.value = true;
|
||||
editing.value = true;
|
||||
mode.value = EditState.Adding;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
|
@ -106,13 +130,14 @@ watch(
|
|||
);
|
||||
|
||||
function saveNewName() {
|
||||
editing.value = false;
|
||||
if (addNew.value) {
|
||||
addNew.value = false;
|
||||
if (mode.value === EditState.Adding) {
|
||||
emit('new', localName.value);
|
||||
} else if (mode.value === EditState.Duplicating) {
|
||||
emit('duplicate', props.modelValue, localName.value);
|
||||
} else {
|
||||
// Editing
|
||||
emit('rename', props.modelValue, localName.value);
|
||||
}
|
||||
mode.value = EditState.None;
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -37,6 +37,12 @@ import {
|
|||
BotDescriptor,
|
||||
BgTaskStarted,
|
||||
BackgroundTaskStatus,
|
||||
Exchange,
|
||||
ExchangeListResult,
|
||||
FreqAIModelListResult,
|
||||
PairlistEvalResponse,
|
||||
PairlistsPayload,
|
||||
PairlistsResponse,
|
||||
} from '@/types';
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { defineStore } from 'pinia';
|
||||
|
@ -44,12 +50,6 @@ import { showAlert } from './alerts';
|
|||
import { useWebSocket } from '@vueuse/core';
|
||||
import { FTWsMessage, FtWsMessageTypes } from '@/types/wsMessageTypes';
|
||||
import { showNotification } from '@/shared/notifications';
|
||||
import {
|
||||
FreqAIModelListResult,
|
||||
PairlistEvalResponse,
|
||||
PairlistsPayload,
|
||||
PairlistsResponse,
|
||||
} from '../types';
|
||||
|
||||
export function createBotSubStore(botId: string, botName: string) {
|
||||
const userService = useUserService(botId);
|
||||
|
@ -91,6 +91,7 @@ export function createBotSubStore(botId: string, botName: string) {
|
|||
strategyPlotConfig: undefined as PlotConfig | undefined,
|
||||
strategyList: [] as string[],
|
||||
freqaiModelList: [] as string[],
|
||||
exchangeList: [] as Exchange[],
|
||||
strategy: {} as StrategyResult,
|
||||
pairlist: [] as string[],
|
||||
currentLocks: undefined as LockResponse | undefined,
|
||||
|
@ -448,6 +449,16 @@ export function createBotSubStore(botId: string, botName: string) {
|
|||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
async getExchangeList() {
|
||||
try {
|
||||
const { data } = await api.get<ExchangeListResult>('/exchanges');
|
||||
this.exchangeList = data.exchanges;
|
||||
return Promise.resolve(data.exchanges);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
async getAvailablePairs(payload: AvailablePairPayload) {
|
||||
try {
|
||||
const { data } = await api.get<AvailablePairResult>('/available_pairs', {
|
||||
|
|
|
@ -72,6 +72,11 @@ export const usePlotConfigStore = defineStore('plotConfig', {
|
|||
this.editablePlotConfig = deepClone(this.customPlotConfigs[this.plotConfigName]);
|
||||
}
|
||||
},
|
||||
duplicatePlotConfig(oldName: string, newName: string) {
|
||||
console.log(oldName, newName);
|
||||
this.customPlotConfigs[newName] = deepClone(this.customPlotConfigs[oldName]);
|
||||
this.plotConfigChanged(newName);
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
key: FT_PLOT_CONFIG_KEY,
|
||||
|
|
|
@ -2,3 +2,6 @@
|
|||
// $body-bg: rgb(42, 42, 49);
|
||||
$font-size-base: 0.9rem;
|
||||
$primary: #0089a1;
|
||||
|
||||
$body-bg-dark: #121212;
|
||||
$body-color-dark: #dedede;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-bs-theme="dark"] {
|
||||
$bg-dark: rgb(18, 18, 18);
|
||||
|
||||
$bg-darker: darken($bg-dark, 5%);
|
||||
|
@ -235,11 +235,14 @@
|
|||
background-color: unset !important;
|
||||
}
|
||||
|
||||
html.ft-theme-transition,
|
||||
html.ft-theme-transition *,
|
||||
html.ft-theme-transition *:before,
|
||||
html.ft-theme-transition *:after {
|
||||
transition: background 750ms ease-in-out,
|
||||
border-color 750ms ease-in-out;
|
||||
body.ft-theme-transition,
|
||||
body.ft-theme-transition *,
|
||||
body.ft-theme-transition *:before,
|
||||
body.ft-theme-transition *:after {
|
||||
transition:
|
||||
background 750ms ease-in-out,
|
||||
border-color 750ms ease-in-out,
|
||||
background-color 750ms ease-in-out,
|
||||
;
|
||||
transition-delay: 0 !important;
|
||||
}
|
||||
|
|
18
src/types/exchange.ts
Normal file
18
src/types/exchange.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { MarginMode, TradingMode } from './types';
|
||||
|
||||
export interface TradeMode {
|
||||
trading_mode: TradingMode;
|
||||
margin_mode: MarginMode;
|
||||
}
|
||||
|
||||
export interface Exchange {
|
||||
name: string;
|
||||
valid: boolean;
|
||||
supported: boolean;
|
||||
comment: string;
|
||||
trade_modes: TradeMode[];
|
||||
}
|
||||
|
||||
export interface ExchangeListResult {
|
||||
exchanges: Exchange[];
|
||||
}
|
|
@ -5,6 +5,7 @@ export * from './balance';
|
|||
export * from './blacklist';
|
||||
export * from './botComparison';
|
||||
export * from './chart';
|
||||
export * from './exchange';
|
||||
export * from './daily';
|
||||
export * from './gridLayout';
|
||||
export * from './locks';
|
||||
|
|
|
@ -80,6 +80,12 @@ export enum TradingMode {
|
|||
FUTURES = 'futures',
|
||||
}
|
||||
|
||||
export enum MarginMode {
|
||||
NONE = 'none',
|
||||
ISOLATED = 'isolated',
|
||||
// CROSS = 'cross',
|
||||
}
|
||||
|
||||
export interface UnfilledTimeout {
|
||||
/** @deprecated replaced by entry in 2.x */
|
||||
buy?: number;
|
||||
|
|
Loading…
Reference in New Issue
Block a user