Update logs and cache marketinfo
This commit is contained in:
@@ -553,7 +553,7 @@ public class TradingBot : Bot, ITradingBot
|
||||
}
|
||||
else
|
||||
{
|
||||
await LogWarning(
|
||||
await LogInformation(
|
||||
$"A position is already open for signal {previousSignal.Identifier}. Position flipping is currently not enable, the position will not be flipped.");
|
||||
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
||||
}
|
||||
@@ -876,8 +876,7 @@ public class TradingBot : Bot, ITradingBot
|
||||
|
||||
private async Task LogWarning(string message)
|
||||
{
|
||||
message = $"[{Name}][{Identifier}] {message}";
|
||||
Logger.LogWarning(message);
|
||||
message = $"[{Identifier}] {message}";
|
||||
SentrySdk.CaptureException(new Exception(message));
|
||||
await SendTradeMessage(message, true);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,49 @@ import {formatUsd} from '../../generated/gmxsdk/utils/numbers/formatting.js';
|
||||
import {calculateDisplayDecimals} from '../../generated/gmxsdk/utils/numbers/index.js';
|
||||
import {handleError} from '../../utils/errorHandler.js';
|
||||
|
||||
// Cache implementation for markets info data
|
||||
interface CacheEntry {
|
||||
data: {
|
||||
marketsInfoData?: MarketsInfoData;
|
||||
tokensData?: TokensData;
|
||||
};
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
const CACHE_TTL = 30 * 60 * 1000; // 30 minutes in milliseconds
|
||||
const marketsCache = new Map<string, CacheEntry>();
|
||||
|
||||
/**
|
||||
* Gets markets info data from cache or fetches it from GMX SDK
|
||||
* @param sdk The GMX SDK client
|
||||
* @returns Markets info data and tokens data
|
||||
*/
|
||||
async function getMarketsInfoWithCache(sdk: GmxSdk): Promise<{ marketsInfoData: MarketsInfoData; tokensData: TokensData }> {
|
||||
const cacheKey = `markets_${sdk.chainId}`;
|
||||
const now = Date.now();
|
||||
const cached = marketsCache.get(cacheKey);
|
||||
|
||||
if (cached && (now - cached.timestamp) < CACHE_TTL) {
|
||||
if (!cached.data.marketsInfoData || !cached.data.tokensData) {
|
||||
throw new Error("Invalid cached data: missing markets or tokens info");
|
||||
}
|
||||
return cached.data as { marketsInfoData: MarketsInfoData; tokensData: TokensData };
|
||||
}
|
||||
|
||||
const data = await sdk.markets.getMarketsInfo();
|
||||
|
||||
if (!data.marketsInfoData || !data.tokensData) {
|
||||
throw new Error("Invalid response from GMX: missing markets or tokens info");
|
||||
}
|
||||
|
||||
marketsCache.set(cacheKey, {
|
||||
data: data as { marketsInfoData: MarketsInfoData; tokensData: TokensData },
|
||||
timestamp: now
|
||||
});
|
||||
|
||||
return data as { marketsInfoData: MarketsInfoData; tokensData: TokensData };
|
||||
}
|
||||
|
||||
/**
|
||||
* GMX Plugin
|
||||
*
|
||||
@@ -99,6 +142,14 @@ export async function getClientForAddress(
|
||||
subgraphUrl: "https://subgraph.satsuma-prod.com/3b2ced13c8d9/gmx/synthetics-arbitrum-stats/api",
|
||||
settings: {
|
||||
uiFeeReceiverAccount: "0xF9f04a745Db54B25bB8B345a1da74D4E3c38c8aB"
|
||||
},
|
||||
markets: {
|
||||
"0x4D3Eb91efd36C2b74181F34B111bc1E91a0d0cb4": {
|
||||
isListed: false,
|
||||
},
|
||||
"0xdf034cd3df9a80eABFA0556232a91E03Ca67D5Cb": {
|
||||
isListed: false,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -136,8 +187,8 @@ export const openGmxPositionImpl = async (
|
||||
takeProfitPrice?: number
|
||||
): Promise<string> => {
|
||||
try {
|
||||
// Get markets and tokens data from GMX SDK
|
||||
const {marketsInfoData, tokensData} = await sdk.markets.getMarketsInfo();
|
||||
// Get markets and tokens data from GMX SDK with cache
|
||||
const {marketsInfoData, tokensData} = await getMarketsInfoWithCache(sdk);
|
||||
|
||||
if (!marketsInfoData || !tokensData) {
|
||||
throw new Error("No markets or tokens info data");
|
||||
@@ -149,7 +200,6 @@ export const openGmxPositionImpl = async (
|
||||
|
||||
// Calculate the collateral amount in USDC (quantity * price)
|
||||
const collateralAmount = BigInt(Math.floor((quantity || 0) * (price || 0) * 1e6)); // USDC has 6 decimals
|
||||
console.log('collateralAmount', collateralAmount);
|
||||
|
||||
// Calculate leverage in basis points (1x = 10000)
|
||||
const leverageBps = BigInt((leverage || 1) * 10000);
|
||||
@@ -168,8 +218,6 @@ export const openGmxPositionImpl = async (
|
||||
takeProfitPrice: takeProfitPrice ? numberToBigint(takeProfitPrice, 30) : undefined
|
||||
};
|
||||
|
||||
console.log('params', params)
|
||||
|
||||
if (direction === TradeDirection.Long) {
|
||||
await sdk.orders.long(params);
|
||||
} else {
|
||||
@@ -391,8 +439,8 @@ export const closeGmxPositionImpl = async (
|
||||
direction: TradeDirection
|
||||
): Promise<string> => {
|
||||
try {
|
||||
// Get markets and tokens data from GMX SDK
|
||||
const {marketsInfoData, tokensData} = await sdk.markets.getMarketsInfo();
|
||||
// Get markets and tokens data from GMX SDK with cache
|
||||
const {marketsInfoData, tokensData} = await getMarketsInfoWithCache(sdk);
|
||||
|
||||
if (!marketsInfoData || !tokensData) {
|
||||
throw new Error("No markets or tokens info data");
|
||||
@@ -525,7 +573,7 @@ export const getGmxTradeImpl = async (
|
||||
ticker: string
|
||||
): Promise<Trade[]> => {
|
||||
|
||||
const {marketsInfoData, tokensData} = await sdk.markets.getMarketsInfo();
|
||||
const {marketsInfoData, tokensData} = await getMarketsInfoWithCache(sdk);
|
||||
|
||||
const orders = await sdk.orders.getOrders({
|
||||
account: sdk.account,
|
||||
@@ -566,7 +614,6 @@ export const getGmxTradeImpl = async (
|
||||
|
||||
if (collateral > 0) {
|
||||
leverage = Math.round(size / collateral);
|
||||
console.log('Calculated leverage:', leverage, 'from size:', size, 'collateral:', collateral);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,7 +688,7 @@ export async function getGmxTrade(
|
||||
export const getGmxPositionsImpl = async (
|
||||
sdk: GmxSdk
|
||||
): Promise<Position[]> => {
|
||||
const {marketsInfoData, tokensData} = await sdk.markets.getMarketsInfo();
|
||||
const {marketsInfoData, tokensData} = await getMarketsInfoWithCache(sdk);
|
||||
|
||||
const positionsInfo = await sdk.positions.getPositionsInfo({
|
||||
marketsInfoData,
|
||||
@@ -651,7 +698,7 @@ export const getGmxPositionsImpl = async (
|
||||
|
||||
const positions = Object.values(positionsInfo).map(async (pos) => {
|
||||
// Fix leverage calculation to avoid exponential notation issues
|
||||
let leverage = 2; // Default to 2x leverage
|
||||
let leverage = 1; // Default to 1x leverage
|
||||
|
||||
if (pos.collateralAmount > 0n) {
|
||||
// Manual calculation of leverage from raw values
|
||||
@@ -783,6 +830,24 @@ export async function getGmxPositions(
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to pre-populate and refresh the markets cache
|
||||
async function getMarketsData() {
|
||||
// Use a dummy zero address for the account
|
||||
const account = "0x0000000000000000000000000000000000000000";
|
||||
const sdk = await getClientForAddress(account);
|
||||
await getMarketsInfoWithCache(sdk);
|
||||
}
|
||||
|
||||
function setupCacheRefresh() {
|
||||
setInterval(async () => {
|
||||
try {
|
||||
await getMarketsData();
|
||||
} catch (error) {
|
||||
console.error('Cache refresh failed:', error);
|
||||
}
|
||||
}, CACHE_TTL);
|
||||
}
|
||||
|
||||
/**
|
||||
* The use of fastify-plugin is required to be able
|
||||
* to export the decorators to the outer scope
|
||||
@@ -797,5 +862,16 @@ export default fp(async (fastify) => {
|
||||
fastify.decorateRequest('closeGmxPosition', closeGmxPosition)
|
||||
fastify.decorateRequest('getGmxTrade', getGmxTrade)
|
||||
fastify.decorateRequest('getGmxPositions', getGmxPositions)
|
||||
|
||||
// Pre-populate and refresh the markets cache on startup
|
||||
fastify.addHook('onReady', async () => {
|
||||
try {
|
||||
await getMarketsData();
|
||||
setupCacheRefresh();
|
||||
} catch (error) {
|
||||
console.error('Initial cache population failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
@@ -126,67 +126,16 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
||||
// Use the existing getClientForAddress function to get a proper GMX SDK instance
|
||||
const sdk = await getClientForAddress(account);
|
||||
|
||||
// Get markets info data
|
||||
// Get the uiFeeFactor - this is a lightweight call
|
||||
const startTime = Date.now();
|
||||
const marketsInfo = await sdk.markets.getMarketsInfo();
|
||||
const responseTime = Date.now() - startTime;
|
||||
|
||||
// Get the uiFeeFactor
|
||||
const uiFeeFactor = await sdk.utils.getUiFeeFactor();
|
||||
|
||||
if (!marketsInfo.marketsInfoData || Object.keys(marketsInfo.marketsInfoData).length === 0) {
|
||||
return {
|
||||
status: 'degraded',
|
||||
message: 'GMX SDK returned empty markets info data',
|
||||
data: {
|
||||
responseTimeMs: responseTime,
|
||||
uiFeeFactor: uiFeeFactor.toString()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Check market data for ETH-USD
|
||||
let foundEthMarket = false;
|
||||
let marketInfoDetails = [];
|
||||
|
||||
// Collect information about all available markets
|
||||
for (const [marketAddress, marketInfo] of Object.entries(marketsInfo.marketsInfoData)) {
|
||||
const marketDetails = {
|
||||
marketAddress,
|
||||
indexToken: marketInfo.indexToken?.symbol,
|
||||
longToken: marketInfo.longToken?.symbol,
|
||||
shortToken: marketInfo.shortToken?.symbol
|
||||
};
|
||||
|
||||
marketInfoDetails.push(marketDetails);
|
||||
|
||||
// Check if this is the ETH market
|
||||
if (marketInfo.indexToken?.symbol === 'ETH' ||
|
||||
marketInfo.indexToken?.symbol === 'WETH' ||
|
||||
marketInfo.indexToken?.name?.includes('Ethereum')) {
|
||||
foundEthMarket = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundEthMarket) {
|
||||
return {
|
||||
status: 'degraded',
|
||||
message: 'ETH market not found in GMX markets data',
|
||||
data: {
|
||||
availableMarkets: marketInfoDetails,
|
||||
responseTimeMs: responseTime,
|
||||
uiFeeFactor: uiFeeFactor.toString()
|
||||
}
|
||||
};
|
||||
}
|
||||
const responseTime = Date.now() - startTime;
|
||||
|
||||
return {
|
||||
status: 'healthy',
|
||||
message: `GMX SDK successfully retrieved markets data (${Object.keys(marketsInfo.marketsInfoData).length} markets)`,
|
||||
message: 'GMX SDK successfully initialized',
|
||||
data: {
|
||||
marketCount: Object.keys(marketsInfo.marketsInfoData).length,
|
||||
responseTimeMs: responseTime,
|
||||
sampleMarkets: marketInfoDetails.slice(0, 3), // Just include first 3 markets for brevity
|
||||
uiFeeFactor: uiFeeFactor.toString()
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user