Add stats and trades to bots
This commit is contained in:
@@ -727,7 +727,8 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
{
|
{
|
||||||
await LogInformation($"Position {signalIdentifier} is now {positionStatus}");
|
await LogInformation($"Position {signalIdentifier} is now {positionStatus}");
|
||||||
Positions.First(p => p.SignalIdentifier == signalIdentifier).Status = positionStatus;
|
Positions.First(p => p.SignalIdentifier == signalIdentifier).Status = positionStatus;
|
||||||
SetSignalStatus(signalIdentifier, SignalStatus.Expired);
|
SetSignalStatus(signalIdentifier,
|
||||||
|
positionStatus == PositionStatus.Filled ? SignalStatus.PositionOpen : SignalStatus.Expired);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus)
|
private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus)
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
import fp from 'fastify-plugin'
|
import fp from 'fastify-plugin'
|
||||||
import {FastifyReply, FastifyRequest, FastifyInstance} from 'fastify'
|
import {FastifyInstance, FastifyReply, FastifyRequest} from 'fastify'
|
||||||
import {z} from 'zod'
|
import {z} from 'zod'
|
||||||
import canonicalize from 'canonicalize'
|
import canonicalize from 'canonicalize'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import {PrivyClient} from '@privy-io/server-auth'
|
import {PrivyClient} from '@privy-io/server-auth'
|
||||||
import {ethers} from 'ethers'
|
import {ethers} from 'ethers'
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
|
import Token from '../../generated/gmxsdk/abis/Token.json' with {type: 'json'}
|
||||||
|
import {ARBITRUM} from '../../generated/gmxsdk/configs/chains.js'
|
||||||
|
import {TOKENS} from '../../generated/gmxsdk/configs/tokens.js'
|
||||||
|
import {CONTRACTS} from '../../generated/gmxsdk/configs/contracts.js'
|
||||||
|
import {getClientForAddress, getTokenDataFromTicker} from './gmx.js'
|
||||||
|
import {Ticker} from '../../generated/ManagingApiTypes.js'
|
||||||
|
import {Address} from 'viem'
|
||||||
|
|
||||||
// Load environment variables
|
// Load environment variables
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
import Token from '../../generated/gmxsdk/abis/Token.json' with { type: 'json' }
|
|
||||||
import { ARBITRUM } from '../../generated/gmxsdk/configs/chains.js'
|
|
||||||
import { TOKENS } from '../../generated/gmxsdk/configs/tokens.js'
|
|
||||||
import { CONTRACTS } from '../../generated/gmxsdk/configs/contracts.js'
|
|
||||||
import { getClientForAddress, getTokenDataFromTicker } from './gmx.js'
|
|
||||||
import { Ticker } from '../../generated/ManagingApiTypes.js'
|
|
||||||
import { Address } from 'viem'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Privy Plugin
|
* Privy Plugin
|
||||||
*
|
*
|
||||||
@@ -72,7 +71,7 @@ export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => {
|
|||||||
walletApi: {
|
walletApi: {
|
||||||
authorizationPrivateKey: authKey
|
authorizationPrivateKey: authKey
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { ArrowDownIcon, ArrowUpIcon } from '@heroicons/react/solid'
|
import {ArrowDownIcon, ArrowUpIcon} from '@heroicons/react/solid'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
|
|
||||||
import type { TradingBot } from '../../../generated/ManagingApi'
|
import useApiUrlStore from '../../../app/store/apiStore'
|
||||||
import { PositionStatus, TradeDirection } from '../../../generated/ManagingApi'
|
import type {PlatformSummaryViewModel, TradingBot} from '../../../generated/ManagingApi'
|
||||||
import type { IAccountBalanceProps } from '../../../global/type'
|
import {DataClient, PositionStatus, TradeDirection} from '../../../generated/ManagingApi'
|
||||||
|
import type {IAccountBalanceProps} from '../../../global/type'
|
||||||
|
|
||||||
|
// Time filter options matching backend
|
||||||
|
const TIME_FILTERS = ['24H', '3D', '1W', '1M', '1Y', 'Total']
|
||||||
|
|
||||||
function GetGlobalWinrate(bots: TradingBot[]) {
|
function GetGlobalWinrate(bots: TradingBot[]) {
|
||||||
if (bots == null || bots == undefined || bots.length == 0) {
|
if (bots == null || bots == undefined || bots.length == 0) {
|
||||||
@@ -55,6 +59,9 @@ function GetPositionCount(
|
|||||||
const Summary: React.FC<IAccountBalanceProps> = ({ bots }) => {
|
const Summary: React.FC<IAccountBalanceProps> = ({ bots }) => {
|
||||||
const [globalPnl, setGlobalPnl] = useState<number>(0)
|
const [globalPnl, setGlobalPnl] = useState<number>(0)
|
||||||
const [globalWinrate, setGlobalWinrate] = useState<number>(0)
|
const [globalWinrate, setGlobalWinrate] = useState<number>(0)
|
||||||
|
const [selectedTimeFilter, setSelectedTimeFilter] = useState<string>('Total')
|
||||||
|
const [platformStats, setPlatformStats] = useState<PlatformSummaryViewModel | null>(null)
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||||
|
|
||||||
const [openLong, setLong] = useState<number>(0)
|
const [openLong, setLong] = useState<number>(0)
|
||||||
const [openShort, setShort] = useState<number>(0)
|
const [openShort, setShort] = useState<number>(0)
|
||||||
@@ -62,6 +69,8 @@ const Summary: React.FC<IAccountBalanceProps> = ({ bots }) => {
|
|||||||
const [closedLong, setClosedLong] = useState<number>(0)
|
const [closedLong, setClosedLong] = useState<number>(0)
|
||||||
const [closedShort, setClosedShort] = useState<number>(0)
|
const [closedShort, setClosedShort] = useState<number>(0)
|
||||||
|
|
||||||
|
const { apiUrl } = useApiUrlStore()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (bots) {
|
if (bots) {
|
||||||
const pnl = bots.reduce((acc, bot) => {
|
const pnl = bots.reduce((acc, bot) => {
|
||||||
@@ -86,9 +95,67 @@ const Summary: React.FC<IAccountBalanceProps> = ({ bots }) => {
|
|||||||
}
|
}
|
||||||
}, [bots])
|
}, [bots])
|
||||||
|
|
||||||
|
// Fetch platform summary data
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchPlatformStats = async () => {
|
||||||
|
setIsLoading(true)
|
||||||
|
try {
|
||||||
|
const dataClient = new DataClient({}, apiUrl)
|
||||||
|
const data = await dataClient.data_GetPlatformSummary(selectedTimeFilter)
|
||||||
|
setPlatformStats(data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching platform stats:', error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchPlatformStats()
|
||||||
|
}, [apiUrl, selectedTimeFilter])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<div className="stats bg-primary text-primary-content mb-4"></div>
|
<div className="mb-4 flex justify-between items-center">
|
||||||
|
<h2 className="text-xl font-bold">Platform Overview</h2>
|
||||||
|
<div className="join">
|
||||||
|
{TIME_FILTERS.map((filter) => (
|
||||||
|
<button
|
||||||
|
key={filter}
|
||||||
|
className={`btn btn-sm join-item ${selectedTimeFilter === filter ? 'btn-primary' : 'btn-ghost'}`}
|
||||||
|
onClick={() => setSelectedTimeFilter(filter)}
|
||||||
|
>
|
||||||
|
{filter}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="stats bg-primary text-primary-content mb-4">
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-title">Total Agents</div>
|
||||||
|
<div className="stat-value">{platformStats?.totalAgents ?? 0}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-title">Active Strategies</div>
|
||||||
|
<div className="stat-value">{platformStats?.totalActiveStrategies ?? 0}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-title">Total Platform PnL</div>
|
||||||
|
<div className="stat-value">{(platformStats?.totalPlatformPnL ?? 0).toFixed(2)} $</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-title">Volume (Total)</div>
|
||||||
|
<div className="stat-value">{(platformStats?.totalPlatformVolume ?? 0).toFixed(2)} $</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-title">Volume (24h)</div>
|
||||||
|
<div className="stat-value">{(platformStats?.totalPlatformVolumeLast24h ?? 0).toFixed(2)} $</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="stats bg-primary text-primary-content">
|
<div className="stats bg-primary text-primary-content">
|
||||||
<div className="stat">
|
<div className="stat">
|
||||||
|
|||||||
Reference in New Issue
Block a user