diff --git a/@models/shannon.ts b/@models/shannon.ts new file mode 100644 index 0000000..dc2deb0 --- /dev/null +++ b/@models/shannon.ts @@ -0,0 +1,51 @@ +import { useCounterParty, useSeriesMap, useSimplePositionManager } from "@libs"; + +// Shannon's re-balance strategy +export default () => { + // Define parameters of the agent + const datasource_id = useParamString('DataSource', 'Y'); + const product_id = useParamString('Product'); + const period = useParamString('Period', 'PT1H'); + // Get the product information and price data + const product = useProduct(datasource_id, product_id); + const { close } = useOHLC(datasource_id, product_id, period); + // More parameters + const initial_balance = useParamNumber('Initial Balance', 100_000); + const threshold = useParamNumber('Threshold', 1); + // Get the account information + const accountInfo = useAccountInfo(); + // Use a simple position manager + const [actualVolume, setVolume] = useSimplePositionManager(accountInfo.account_id, product_id); + // Re-balance the position + useEffect(() => { + if (close.length < 2) return; + const price = close[close.length - 1]; + const totalValue = accountInfo.money.equity + initial_balance; + const totalValueToHold = totalValue * 0.5; + // infer the volume to hold + const valuePerVolume = + price * (product.value_speed ?? 1) * (product.is_underlying_base_currency ? -1 / price : 1); + const expectedVolume = totalValueToHold / valuePerVolume; + // calculate the error rate + const volume_step = product.volume_step ?? 1; + const errorRate = Math.abs((actualVolume - expectedVolume) / volume_step); + if (errorRate > threshold) { + setVolume(roundToStep(expectedVolume, volume_step)); + } + }, [close.length]); + // Advanced: Visualize the equity and margin + useSeriesMap( + "Equity", + close, + { display: "line", chart: "new" }, + () => accountInfo.money.equity + ); + useSeriesMap( + "Margin", + close, + { display: "line", chart: "new" }, + () => accountInfo.money.used + ); + // Advanced: use counter-party to show if we take the opposite position + useCounterParty(accountInfo.account_id); +}; diff --git a/global.d.ts b/global.d.ts index f97da62..3773a91 100644 --- a/global.d.ts +++ b/global.d.ts @@ -583,6 +583,25 @@ declare const useRecordTable: >( declare const formatTime: (timestamp: number) => string; /** Generate a UUID (Universal-Unique-ID) */ declare const UUID: () => string; +declare const roundToStep: ( + value: number, + step: number, + roundFn?: ((x: number) => number) | undefined +) => number; +declare const getProfit: ( + product: IProduct, + openPrice: number, + closePrice: number, + volume: number, + variant: string, + currency: string, + quotes: (product_id: string) => + | { + ask: number; + bid: number; + } + | undefined +) => number; // Deployment script context /**