diff --git a/.env b/.env index e31db3d33..18d1741f2 100644 --- a/.env +++ b/.env @@ -31,7 +31,7 @@ TS_PUBLIC_TYPESENSE_API_URL=https://typesense.tradingstrategy.ai TS_PUBLIC_TYPESENSE_API_KEY=npdPPJNELDhdr7v6IS9rQUpFG2VvdyAL TS_PUBLIC_DISCORD_URL=https://discord.gg/5M88m9nM8H TS_PUBLIC_WALLET_CONNECT_PROJECT_ID=9ee7efad98897eb60ba023db6aa72355 -TS_PUBLIC_STRATEGIES='[{"id":"enzyme-polygon-eth-btc-rsi","name":"ETH-BTC price surge","url":"https://enzyme-polygon-eth-btc-rsi.tradingstrategy.ai/","frontpage":true},{"id":"enzyme-ethereum-btc-eth-stoch-rsi","name":"Stochastic ETH/BTC long","url":"https://enzyme-ethereum-btc-eth-stoch-rsi.tradingstrategy.ai","fees":{"trading_strategy_protocol_fee":0.02,"strategy_developer_fee":0.1},"frontpage":true},{"id":"enzyme-polygon-eth-rolling-ratio","name":"ETH/BTC rolling ratio","url":"https://enzyme-polygon-eth-rolling-ratio.tradingstrategy.ai/","fees":{"trading_strategy_protocol_fee":0.02,"strategy_developer_fee":0.05},"frontpage":true},{"id":"enzyme-polygon-matic-eth-usdc","name":"ETH-MATIC-USDC momentum","url":"https://enzyme-polygon-matic-eth-usdc.tradingstrategy.ai","frontpage":true},{"id":"enzyme-polygon-eth-btc-usdc","name":"ETH-BTC-USDC momentum","url":"https://enzyme-polygon-eth-btc-usdc.tradingstrategy.ai","new_version_id":"enzyme-polygon-eth-btc-rsi","frontpage":true},{"id":"enzyme-polygon-matic-usdc","name":"MATIC breakout","url":"https://enzyme-polygon-matic-usdc.tradingstrategy.ai"},{"id":"enzyme-polygon-eth-breakout","name":"ETH breakout","url":"https://enzyme-polygon-eth-breakout.tradingstrategy.ai"},{"id":"enzyme-polygon-eth-usdc","name":"ETH Breakout bounce","url":"https://enzyme-polygon-eth-usdc.tradingstrategy.ai"},{"id":"enzyme-polygon-eth-usdc-sls","name":"ETH Balance snap","url":"https://enzyme-polygon-eth-usdc-sls.tradingstrategy.ai"},{"id":"polygon-eth-spot-short","name":"ETH mean reversion bounce","url":"https://polygon-eth-spot-short.tradingstrategy.ai"},{"id":"arbitrum-btc-breakout","name":"BTC Barrier Breach","url":"https://arbitrum-btc-breakout.tradingstrategy.ai"}]' +TS_PUBLIC_STRATEGIES='[{"id":"enzyme-polygon-eth-btc-rsi","name":"ETH-BTC price surge","url":"https://enzyme-polygon-eth-btc-rsi.tradingstrategy.ai/","frontpage":true,"hiddenPositions":[4]},{"id":"enzyme-ethereum-btc-eth-stoch-rsi","name":"Stochastic ETH/BTC long","url":"https://enzyme-ethereum-btc-eth-stoch-rsi.tradingstrategy.ai","fees":{"trading_strategy_protocol_fee":0.02,"strategy_developer_fee":0.1},"frontpage":true},{"id":"enzyme-polygon-eth-rolling-ratio","name":"ETH/BTC rolling ratio","url":"https://enzyme-polygon-eth-rolling-ratio.tradingstrategy.ai/","fees":{"trading_strategy_protocol_fee":0.02,"strategy_developer_fee":0.05},"frontpage":true},{"id":"enzyme-polygon-matic-eth-usdc","name":"ETH-MATIC-USDC momentum","url":"https://enzyme-polygon-matic-eth-usdc.tradingstrategy.ai","frontpage":true},{"id":"enzyme-polygon-eth-btc-usdc","name":"ETH-BTC-USDC momentum","url":"https://enzyme-polygon-eth-btc-usdc.tradingstrategy.ai","new_version_id":"enzyme-polygon-eth-btc-rsi","frontpage":true},{"id":"enzyme-polygon-matic-usdc","name":"MATIC breakout","url":"https://enzyme-polygon-matic-usdc.tradingstrategy.ai"},{"id":"enzyme-polygon-eth-breakout","name":"ETH breakout","url":"https://enzyme-polygon-eth-breakout.tradingstrategy.ai"},{"id":"enzyme-polygon-eth-usdc","name":"ETH Breakout bounce","url":"https://enzyme-polygon-eth-usdc.tradingstrategy.ai"},{"id":"enzyme-polygon-eth-usdc-sls","name":"ETH Balance snap","url":"https://enzyme-polygon-eth-usdc-sls.tradingstrategy.ai"},{"id":"polygon-eth-spot-short","name":"ETH mean reversion bounce","url":"https://polygon-eth-spot-short.tradingstrategy.ai"},{"id":"arbitrum-btc-breakout","name":"BTC Barrier Breach","url":"https://arbitrum-btc-breakout.tradingstrategy.ai"}]' TS_PUBLIC_GEO_BLOCK='{"strategies:view":["CU","IR","KP","RU","SY"],"strategies:deposit":["CU","IR","KP","RU","SY","US","UK"]}' # Uncomment to test chain maintenance error # TS_PUBLIC_CHAINS_UNDER_MAINTENANCE='{ "binance": "BNB Chain" }' diff --git a/src/lib/explorer/TradingDescription.svelte b/src/lib/explorer/TradingDescription.svelte index e8aa84307..bf07780ec 100644 --- a/src/lib/explorer/TradingDescription.svelte +++ b/src/lib/explorer/TradingDescription.svelte @@ -19,13 +19,15 @@ Used in DataTable context (vs. standard svelte component context). -
+
{label} diff --git a/src/lib/trade-executor/strategy/configuration.ts b/src/lib/trade-executor/strategy/configuration.ts index fdf7bcfaf..974f85fcf 100644 --- a/src/lib/trade-executor/strategy/configuration.ts +++ b/src/lib/trade-executor/strategy/configuration.ts @@ -1,6 +1,6 @@ import { strategyConfig } from '$lib/config'; import { z } from 'zod'; -import { percent } from '../state/utility-types'; +import { percent, primaryKey } from '../state/utility-types'; export const strategyFeesSchema = z.object({ management_fee: percent.default(0), @@ -16,7 +16,8 @@ export const strategyConfigurationSchema = z.object({ url: z.string().url(), fees: strategyFeesSchema.default({}), new_version_id: z.string().nullish(), - frontpage: z.boolean().nullish() + frontpage: z.boolean().nullish(), + hiddenPositions: primaryKey.array().default([]) }); export type StrategyConfiguration = z.infer; diff --git a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.svelte b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.svelte index 9687c8661..b08bef3ba 100644 --- a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.svelte +++ b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.svelte @@ -45,6 +45,7 @@ {...options} hasPagination={status === 'closed'} hasSearch={status === 'closed'} + hiddenPositions={strategy.hiddenPositions} on:change={handleChange} /> {:else} diff --git a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.ts b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.ts index 137016149..6fad821cb 100644 --- a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.ts +++ b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/+page.ts @@ -3,9 +3,14 @@ import { getTradingPositionInfoArray } from 'trade-executor/state/position-info. export async function load({ params, parent }) { // status can be `open`, `closed` or `frozen` (see params/positionStatus.ts) const { status } = params; - const { state } = await parent(); + const { admin, strategy, state } = await parent(); + const { hiddenPositions } = strategy; - const positions = getTradingPositionInfoArray(state, status); + let positions = getTradingPositionInfoArray(state, status); + + if (!admin) { + positions = positions.filter((p) => !hiddenPositions.includes(p.position_id)); + } return { positions, status }; } diff --git a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/FlagCell.svelte b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/FlagCell.svelte index 82e614945..877fffd85 100644 --- a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/FlagCell.svelte +++ b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/FlagCell.svelte @@ -8,6 +8,7 @@ export let admin = false; export let position: TradingPositionInfo; export let baseUrl: string; + export let isHidden = false; function getTradeLink(trade: TradeInfo) { return `${baseUrl}/trade-${trade.trade_id}`; @@ -83,6 +84,19 @@ {/if} + + {#if admin && isHidden} + +

+ This info is only displayed to admin users. +

+

This position is hidden from non-admin users.

+

+ Hidden positions are configured in frontend strategy configuration (on production, in the + strategy.json config file). +

+
+ {/if}
diff --git a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/PositionTable.svelte b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/PositionTable.svelte index 14bf0d947..342dfd1e1 100644 --- a/src/routes/strategies/[strategy]/[status=positionStatus]-positions/PositionTable.svelte +++ b/src/routes/strategies/[strategy]/[status=positionStatus]-positions/PositionTable.svelte @@ -21,6 +21,7 @@ export let direction: 'asc' | 'desc' = 'desc'; export let hasSearch = false; export let hasPagination = false; + export let hiddenPositions: number[] = []; const positionsStore = writable([] as TradingPositionInfo[]); $: positionsStore.set(positions); @@ -53,7 +54,12 @@ table.column({ header: 'Position', id: 'description', - accessor: ({ pair, isTest }) => ({ label: pair.symbol, modifier: pair.kindShortLabel, isTest }), + accessor: ({ position_id, pair, isTest }) => ({ + class: hiddenPositions.includes(position_id) ? 'hidden' : '', + label: pair.symbol, + modifier: pair.kindShortLabel, + isTest + }), cell: ({ value }) => createRender(TradingDescription, value) }), table.column({ @@ -61,7 +67,12 @@ id: 'flags', accessor: (position) => position, cell: ({ value }) => - createRender(FlagCell, { admin, position: value, baseUrl: `./${status}-positions/${value.position_id}` }), + createRender(FlagCell, { + admin, + position: value, + baseUrl: `./${status}-positions/${value.position_id}`, + isHidden: hiddenPositions.includes(value.position_id) + }), plugins: { sort: { disable: true } } }), table.column({ @@ -141,6 +152,23 @@ } .position-table :global { + /* Make "hidden" position rows look 50% opaque w/out breaking nested tooltip style */ + tr:has(.hidden) { + td { + background: var(--c-box-1); + } + + /* only apply color-mix to text in leaf nodes */ + *:not(:has(> *)) { + color: color-mix(in srgb, currentColor, var(--c-body) 50%); + } + + /* revert the color-mix 50% opacity for the tooltip */ + .tooltip .popup * { + color: var(--c-text); + } + } + .ticker { white-space: pre; }