2023-05-29 21:36:23 +00:00
|
|
|
import { defineStore } from 'pinia';
|
|
|
|
import { useBotStore } from './ftbotwrapper';
|
|
|
|
|
2023-05-30 11:41:37 +00:00
|
|
|
import {
|
2023-06-04 11:41:14 +00:00
|
|
|
ExchangeSelection,
|
|
|
|
MarginMode,
|
2023-05-30 11:41:37 +00:00
|
|
|
Pairlist,
|
|
|
|
PairlistConfig,
|
|
|
|
PairlistParamType,
|
2023-06-10 06:46:36 +00:00
|
|
|
PairlistParamValue,
|
2023-05-30 11:41:37 +00:00
|
|
|
PairlistPayloadItem,
|
|
|
|
PairlistsPayload,
|
2023-06-04 11:41:14 +00:00
|
|
|
TradingMode,
|
2023-05-30 11:41:37 +00:00
|
|
|
} from '@/types';
|
2023-06-07 17:26:33 +00:00
|
|
|
import { computed, ref, toRaw, watch } from 'vue';
|
2023-05-29 21:36:23 +00:00
|
|
|
import { showAlert } from './alerts';
|
2023-06-10 06:53:45 +00:00
|
|
|
import { isNotUndefined } from '@/shared/formatters';
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
export const usePairlistConfigStore = defineStore(
|
|
|
|
'pairlistConfig',
|
|
|
|
() => {
|
|
|
|
const botStore = useBotStore();
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
const evaluating = ref<boolean>(false);
|
|
|
|
const intervalId = ref<number>();
|
2023-06-02 08:02:13 +00:00
|
|
|
const stakeCurrency = ref<string>(botStore.activeBot?.stakeCurrency ?? 'USDT');
|
2023-05-29 22:24:48 +00:00
|
|
|
const whitelist = ref<string[]>([]);
|
2023-06-04 11:41:14 +00:00
|
|
|
const customExchange = ref<boolean>(false);
|
|
|
|
const selectedExchange = ref<ExchangeSelection>({
|
2023-06-04 13:45:49 +00:00
|
|
|
exchange: botStore.activeBot?.botState.exchange ?? '',
|
2023-06-04 11:41:14 +00:00
|
|
|
trade_mode: {
|
2023-06-04 13:45:49 +00:00
|
|
|
trading_mode: botStore.activeBot?.botState.trading_mode ?? TradingMode.SPOT,
|
|
|
|
margin_mode:
|
|
|
|
botStore.activeBot?.botState.trading_mode === TradingMode.FUTURES
|
|
|
|
? MarginMode.ISOLATED
|
|
|
|
: MarginMode.NONE,
|
2023-06-04 11:41:14 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-06-09 11:02:21 +00:00
|
|
|
const config = ref<PairlistConfig>(makeConfig());
|
2023-05-29 22:24:48 +00:00
|
|
|
const savedConfigs = ref<PairlistConfig[]>([]);
|
2023-06-07 17:26:33 +00:00
|
|
|
const configName = ref<string>('');
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
const firstPairlistIsGenerator = computed<boolean>(() => {
|
|
|
|
// First pairlist must be a generator
|
|
|
|
if (config.value.pairlists[0]?.is_pairlist_generator) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
const pairlistValid = computed<boolean>(() => {
|
|
|
|
return firstPairlistIsGenerator.value && config.value.pairlists.length > 0;
|
|
|
|
});
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-05-30 11:41:37 +00:00
|
|
|
const configJSON = computed(() => {
|
|
|
|
return JSON.stringify(configToPayloadItems(), null, 2);
|
|
|
|
});
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-06-09 19:32:47 +00:00
|
|
|
const isSavedConfig = (name: string) =>
|
|
|
|
savedConfigs.value.findIndex((c) => c.name === name) > -1;
|
2023-05-30 15:51:19 +00:00
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
function addToConfig(pairlist: Pairlist, index: number) {
|
|
|
|
pairlist = structuredClone(toRaw(pairlist));
|
2023-06-13 13:00:45 +00:00
|
|
|
pairlist.showParameters = false;
|
|
|
|
if (!pairlist.id) {
|
|
|
|
pairlist.id = Date.now().toString(36) + Math.random().toString(36).substring(2);
|
|
|
|
}
|
2023-05-29 22:24:48 +00:00
|
|
|
for (const param in pairlist.params) {
|
2023-06-10 06:53:45 +00:00
|
|
|
pairlist.params[param].value = isNotUndefined(pairlist.params[param].default)
|
|
|
|
? pairlist.params[param].default
|
2023-05-29 22:24:48 +00:00
|
|
|
: '';
|
|
|
|
}
|
|
|
|
config.value.pairlists.splice(index, 0, pairlist);
|
2023-05-29 21:36:23 +00:00
|
|
|
}
|
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
function removeFromConfig(index: number) {
|
|
|
|
config.value.pairlists.splice(index, 1);
|
|
|
|
}
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-06-07 17:26:33 +00:00
|
|
|
function saveConfig(name = '') {
|
2023-05-29 22:24:48 +00:00
|
|
|
const i = savedConfigs.value.findIndex((c) => c.name === config.value.name);
|
2023-06-07 17:26:33 +00:00
|
|
|
config.value.name = name;
|
2023-05-29 21:36:23 +00:00
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
if (i > -1) {
|
2023-06-07 17:26:33 +00:00
|
|
|
savedConfigs.value[i] = structuredClone(toRaw(config.value));
|
2023-05-29 22:24:48 +00:00
|
|
|
} else {
|
2023-06-07 17:26:33 +00:00
|
|
|
savedConfigs.value.push(structuredClone(toRaw(config.value)));
|
2023-05-29 22:24:48 +00:00
|
|
|
}
|
2023-05-30 10:42:17 +00:00
|
|
|
}
|
|
|
|
|
2023-06-06 14:39:32 +00:00
|
|
|
function newConfig(name: string) {
|
2023-06-09 11:02:21 +00:00
|
|
|
const c = makeConfig({ name });
|
2023-06-06 14:39:32 +00:00
|
|
|
savedConfigs.value.push(c);
|
2023-06-07 17:26:33 +00:00
|
|
|
config.value = structuredClone(c);
|
2023-06-06 14:39:32 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 17:26:33 +00:00
|
|
|
function duplicateConfig(name = '') {
|
2023-06-09 11:02:21 +00:00
|
|
|
const c = makeConfig({
|
|
|
|
name,
|
|
|
|
pairlists: toRaw(config.value.pairlists) as [],
|
|
|
|
blacklist: toRaw(config.value.blacklist) as [],
|
|
|
|
});
|
2023-06-06 14:39:32 +00:00
|
|
|
savedConfigs.value.push(c);
|
2023-06-07 17:26:33 +00:00
|
|
|
config.value = structuredClone(c);
|
2023-06-01 23:44:04 +00:00
|
|
|
}
|
|
|
|
|
2023-05-30 15:44:38 +00:00
|
|
|
function deleteConfig() {
|
|
|
|
const i = savedConfigs.value.findIndex((c) => c.name === config.value.name);
|
|
|
|
if (i > -1) {
|
|
|
|
savedConfigs.value.splice(i, 1);
|
2023-06-07 17:26:33 +00:00
|
|
|
selectOrCreateConfig(
|
|
|
|
savedConfigs.value.length > 0 ? savedConfigs.value[0].name : 'default',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function selectOrCreateConfig(name: string) {
|
|
|
|
const c = savedConfigs.value.find((c) => name === c.name);
|
|
|
|
if (c) {
|
|
|
|
config.value = structuredClone(toRaw(c));
|
|
|
|
} else {
|
|
|
|
newConfig(name);
|
2023-05-30 15:44:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-09 11:02:21 +00:00
|
|
|
function makeConfig({ name = '', pairlists = [], blacklist = [] } = {}): PairlistConfig {
|
|
|
|
return { name, pairlists, blacklist };
|
|
|
|
}
|
|
|
|
|
2023-05-30 11:28:55 +00:00
|
|
|
function addToBlacklist() {
|
2023-06-09 11:02:21 +00:00
|
|
|
config.value.blacklist.push('');
|
2023-05-30 11:28:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function removeFromBlacklist(index: number) {
|
2023-06-09 11:02:21 +00:00
|
|
|
config.value.blacklist.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function duplicateBlacklist(configName: string) {
|
|
|
|
const conf = savedConfigs.value.find((c) => c.name === configName);
|
|
|
|
if (conf) {
|
|
|
|
config.value.blacklist = structuredClone(toRaw(conf.blacklist));
|
|
|
|
}
|
2023-05-30 11:28:55 +00:00
|
|
|
}
|
|
|
|
|
2023-05-30 11:41:37 +00:00
|
|
|
async function startPairlistEvaluation() {
|
|
|
|
const payload: PairlistsPayload = configToPayload();
|
|
|
|
|
|
|
|
evaluating.value = true;
|
2023-06-04 11:41:14 +00:00
|
|
|
try {
|
|
|
|
const { job_id: jobId } = await botStore.activeBot.evaluatePairlist(payload);
|
|
|
|
console.log('jobId', jobId);
|
|
|
|
|
|
|
|
intervalId.value = setInterval(async () => {
|
|
|
|
const res = await botStore.activeBot.getBackgroundJobStatus(jobId);
|
|
|
|
if (!res.running) {
|
|
|
|
clearInterval(intervalId.value);
|
|
|
|
const wl = await botStore.activeBot.getPairlistEvalResult(jobId);
|
2023-05-31 18:22:36 +00:00
|
|
|
evaluating.value = false;
|
2023-06-04 11:41:14 +00:00
|
|
|
if (wl.status === 'success') {
|
|
|
|
whitelist.value = wl.result.whitelist;
|
|
|
|
} else if (wl.error) {
|
|
|
|
showAlert(wl.error, 'danger');
|
|
|
|
evaluating.value = false;
|
|
|
|
}
|
2023-05-31 18:22:36 +00:00
|
|
|
}
|
2023-06-04 11:41:14 +00:00
|
|
|
}, 1000);
|
|
|
|
} catch (error) {
|
|
|
|
showAlert('Evaluation failed', 'danger');
|
|
|
|
evaluating.value = false;
|
|
|
|
}
|
2023-05-30 11:41:37 +00:00
|
|
|
}
|
|
|
|
|
2023-06-10 06:46:36 +00:00
|
|
|
function convertToParamType(type: PairlistParamType, value: PairlistParamValue) {
|
2023-05-30 11:41:37 +00:00
|
|
|
if (type === PairlistParamType.number) {
|
|
|
|
return Number(value);
|
|
|
|
} else if (type === PairlistParamType.boolean) {
|
|
|
|
return Boolean(value);
|
|
|
|
} else {
|
|
|
|
return String(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-02 08:02:13 +00:00
|
|
|
function configToPayload(): PairlistsPayload {
|
2023-05-30 11:41:37 +00:00
|
|
|
const pairlists: PairlistPayloadItem[] = configToPayloadItems();
|
2023-06-09 11:02:21 +00:00
|
|
|
const c: PairlistsPayload = {
|
2023-05-30 11:41:37 +00:00
|
|
|
pairlists: pairlists,
|
2023-06-02 08:02:13 +00:00
|
|
|
stake_currency: stakeCurrency.value,
|
2023-06-09 11:02:21 +00:00
|
|
|
blacklist: config.value.blacklist,
|
2023-05-30 11:41:37 +00:00
|
|
|
};
|
2023-06-04 11:41:14 +00:00
|
|
|
if (customExchange.value) {
|
|
|
|
console.log('setting custom exchange props');
|
2023-06-09 11:02:21 +00:00
|
|
|
c.exchange = selectedExchange.value.exchange;
|
|
|
|
c.trading_mode = selectedExchange.value.trade_mode.trading_mode;
|
|
|
|
c.margin_mode = selectedExchange.value.trade_mode.margin_mode;
|
2023-06-04 11:41:14 +00:00
|
|
|
}
|
2023-06-09 11:02:21 +00:00
|
|
|
return c;
|
2023-05-30 11:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function configToPayloadItems() {
|
|
|
|
const pairlists: PairlistPayloadItem[] = [];
|
|
|
|
config.value.pairlists.forEach((config) => {
|
|
|
|
const pairlist = {
|
|
|
|
method: config.name,
|
|
|
|
};
|
|
|
|
for (const key in config.params) {
|
|
|
|
const param = config.params[key];
|
|
|
|
if (param.value) {
|
|
|
|
pairlist[key] = convertToParamType(param.type, param.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pairlists.push(pairlist);
|
|
|
|
});
|
|
|
|
|
|
|
|
return pairlists;
|
|
|
|
}
|
|
|
|
|
2023-06-07 17:26:33 +00:00
|
|
|
watch(
|
|
|
|
() => config.value,
|
|
|
|
() => {
|
|
|
|
configName.value = config.value.name;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
deep: true,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2023-05-29 22:24:48 +00:00
|
|
|
return {
|
|
|
|
evaluating,
|
|
|
|
whitelist,
|
|
|
|
config,
|
2023-05-30 11:41:37 +00:00
|
|
|
configJSON,
|
2023-05-29 22:24:48 +00:00
|
|
|
savedConfigs,
|
2023-06-07 17:26:33 +00:00
|
|
|
configName,
|
2023-05-29 22:24:48 +00:00
|
|
|
startPairlistEvaluation,
|
|
|
|
addToConfig,
|
|
|
|
removeFromConfig,
|
2023-06-07 17:26:33 +00:00
|
|
|
saveConfig,
|
2023-06-06 14:39:32 +00:00
|
|
|
duplicateConfig,
|
2023-05-30 15:44:38 +00:00
|
|
|
deleteConfig,
|
2023-05-30 10:42:17 +00:00
|
|
|
newConfig,
|
2023-06-07 17:26:33 +00:00
|
|
|
selectOrCreateConfig,
|
2023-05-30 11:28:55 +00:00
|
|
|
addToBlacklist,
|
|
|
|
removeFromBlacklist,
|
2023-06-09 11:02:21 +00:00
|
|
|
duplicateBlacklist,
|
2023-05-30 15:51:19 +00:00
|
|
|
isSavedConfig,
|
2023-05-29 22:24:48 +00:00
|
|
|
firstPairlistIsGenerator,
|
|
|
|
pairlistValid,
|
2023-06-02 08:02:13 +00:00
|
|
|
stakeCurrency,
|
2023-06-04 11:41:14 +00:00
|
|
|
customExchange,
|
|
|
|
selectedExchange,
|
2023-05-29 22:24:48 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
{
|
|
|
|
persist: {
|
2023-06-07 17:26:33 +00:00
|
|
|
key: 'ftPairlistConfig',
|
2023-06-09 19:32:47 +00:00
|
|
|
paths: ['savedConfigs', 'configName'],
|
2023-05-29 22:24:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|