diff --git a/src/lib/explorer/TradingDescription.svelte b/src/lib/explorer/TradingDescription.svelte index bf07780ec..fcee437f8 100644 --- a/src/lib/explorer/TradingDescription.svelte +++ b/src/lib/explorer/TradingDescription.svelte @@ -7,7 +7,7 @@ primary label, a modifier (shown in lighter text), and a testing indicator Used in DataTable context (vs. standard svelte component context). #### Usage: -```ts +```tsx table.column({ header: 'Position', id: 'description', diff --git a/src/lib/trade-executor/components/StrategyError.svelte b/src/lib/trade-executor/components/StrategyError.svelte new file mode 100644 index 000000000..51706a672 --- /dev/null +++ b/src/lib/trade-executor/components/StrategyError.svelte @@ -0,0 +1,50 @@ + + + + + + +{#if !strategy.connected} + Trade executor offline. Cannot display the strategy statistics. +{:else if !strategy.executor_running} + Strategy execution is currently paused due to an error. The trade execution engine is waiting for a manual action. + {#if strategy.crashed_at} + + Strategy executor halted {relative}. + + {/if} + See instance status page for more information . +{:else if strategy.frozen_positions > 0} + Strategy has currently frozen trading positions that require manual intervention. + See frozen positions page for more information. +{/if} diff --git a/src/lib/trade-executor/components/index.ts b/src/lib/trade-executor/components/index.ts index 9cb883533..087677004 100644 --- a/src/lib/trade-executor/components/index.ts +++ b/src/lib/trade-executor/components/index.ts @@ -1,3 +1,5 @@ export { default as KeyMetric } from './KeyMetric.svelte'; export { default as KeyMetricDescription } from './KeyMetricDescription.svelte'; export { default as StrategyIcon } from './StrategyIcon.svelte'; +export { default as StrategyError } from './StrategyError.svelte'; +export * from './StrategyError.svelte'; diff --git a/src/lib/trade-executor/strategy/error.ts b/src/lib/trade-executor/strategy/error.ts deleted file mode 100644 index 45cace6b6..000000000 --- a/src/lib/trade-executor/strategy/error.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Strategy error handling. - * - * There can be multiple failure modes for a trade executor - * - * - No connection - the webhook server is down / Internet issue - * - * - The trade executor has halted, the main loop aborted with an exception - * - * - The trade executor is not halted, but there is capital tied at - * frozen positions that need manual interventino - */ - -import type { StrategyRuntimeState } from './runtime-state'; -import { fromUnixTime } from 'date-fns'; -import { formatDatetime, formatDuration } from '$lib/helpers/formatters'; - -/** - * Get the HTML error message and help link in the case a trade executor is facing an issue. - */ -export function getTradeExecutorErrorHtml(state: StrategyRuntimeState): string | null { - const tradeExecutorId = state.id; - - if (!state.connected) { - return `Trade executor offline. Cannot display the strategy statistics.`; - } else if (!state.executor_running) { - // Add a timestamp and relative timestamp for quick diagnostics - let crashedAtMsg; - if (state.crashed_at) { - const diffSeconds = Date.now() / 1000 - state.crashed_at; - crashedAtMsg = `Strategy executor halted ${formatDatetime(fromUnixTime(state.crashed_at))}, ${formatDuration( - diffSeconds - )} ago.`; - } else { - crashedAtMsg = ''; - } - - return `Strategy execution is currently paused due to an error. The trade execution engine is waiting for a manual action. - See instance status page for more information. ${crashedAtMsg}`; - } else if (state.frozen_positions > 0) { - return `Strategy has currently frozen trading positions that needing manual actions. - See frozen positions page for more information.`; - } - - return null; -} diff --git a/src/routes/strategies/StrategyTile.svelte b/src/routes/strategies/StrategyTile.svelte index 35437e722..acb4250eb 100644 --- a/src/routes/strategies/StrategyTile.svelte +++ b/src/routes/strategies/StrategyTile.svelte @@ -5,13 +5,13 @@ import { utcDay } from 'd3-time'; import { normalizeDataForInterval } from '$lib/chart'; import { getChain } from '$lib/helpers/chain.js'; - import { Button, DataBadge, EntitySymbol, Tooltip } from '$lib/components'; - import { StrategyIcon } from 'trade-executor/components'; + import { Button, DataBadge, Tooltip } from '$lib/components'; + import { StrategyIcon, StrategyError, shouldDisplayError, adminOnlyError } from 'trade-executor/components'; import StrategyBadges from './StrategyBadges.svelte'; import ChartThumbnail from './ChartThumbnail.svelte'; import StrategyDataSummary from './StrategyDataSummary.svelte'; - import { getTradeExecutorErrorHtml } from 'trade-executor/strategy/error'; import { getLogoUrl } from '$lib/helpers/assets'; + import Alert from '$lib/components/Alert.svelte'; export let admin = false; export let simplified = false; @@ -21,7 +21,6 @@ const chain = getChain(strategy.on_chain_data?.chain_id); const href = `/strategies/${strategy.id}`; - const errorHtml = getTradeExecutorErrorHtml(strategy); const chartData = normalizeDataForInterval( strategy.summary_statistics?.compounding_unrealised_trading_profitability ?? [], @@ -53,10 +52,17 @@ {#if !simplified}
- {#if errorHtml} + {#if shouldDisplayError(strategy, admin)} Error - {@html errorHtml} + + {#if adminOnlyError(strategy)} +

+ This error is only displayed to admin users. +

+ {/if} + +
{/if} diff --git a/src/routes/strategies/[strategy]/+layout.svelte b/src/routes/strategies/[strategy]/+layout.svelte index 3b5414f6e..6b7079da7 100644 --- a/src/routes/strategies/[strategy]/+layout.svelte +++ b/src/routes/strategies/[strategy]/+layout.svelte @@ -2,19 +2,18 @@ import { page } from '$app/stores'; import Breadcrumbs from '$lib/breadcrumb/Breadcrumbs.svelte'; import { AlertList, PageHeading } from '$lib/components'; - import { StrategyIcon } from 'trade-executor/components'; + import { StrategyIcon, StrategyError, shouldDisplayError, adminOnlyError } from 'trade-executor/components'; import { menuOptions, default as StrategyNav } from './StrategyNav.svelte'; import StrategyBadges from '../StrategyBadges.svelte'; import { WalletWidget } from '$lib/wallet'; - import { getTradeExecutorErrorHtml } from 'trade-executor/strategy/error'; export let data; - $: ({ strategy, deferred } = data); + $: ({ admin, strategy, deferred } = data); $: isOverviewPage = $page.url.pathname.endsWith(strategy.id); - $: errorHtml = getTradeExecutorErrorHtml(strategy); + $: hasStrategyError = shouldDisplayError(strategy, admin); $: isOutdated = Boolean(strategy.new_version_id); @@ -42,7 +41,7 @@
- {#if isOverviewPage && (errorHtml || isOutdated)} + {#if isOverviewPage && (hasStrategyError || isOutdated)}
@@ -51,8 +50,11 @@ participants should consider tranfering deposits to the latest version (though there is no guarantee of better performance). - - {@html errorHtml} + + + {#if adminOnlyError(strategy)} +

Note: this error is only displayed to admin users.

+ {/if}
@@ -82,6 +84,11 @@ transform: translate(0, -0.375em); } + .admin-error { + margin-top: 1rem; + opacity: 0.5; + } + .subpage { display: grid; gap: var(--space-ls);