Update open interest
This commit is contained in:
@@ -25,6 +25,7 @@ public interface ITradingRepository
|
|||||||
Task<Position> GetPositionByIdentifierAsync(Guid identifier);
|
Task<Position> GetPositionByIdentifierAsync(Guid identifier);
|
||||||
Task<IEnumerable<Position>> GetPositionsAsync(PositionInitiator positionInitiator);
|
Task<IEnumerable<Position>> GetPositionsAsync(PositionInitiator positionInitiator);
|
||||||
Task<IEnumerable<Position>> GetPositionsByStatusAsync(PositionStatus positionStatus);
|
Task<IEnumerable<Position>> GetPositionsByStatusAsync(PositionStatus positionStatus);
|
||||||
|
Task<IEnumerable<Position>> GetAllPositionsAsync();
|
||||||
|
|
||||||
Task UpdateScenarioAsync(Scenario scenario);
|
Task UpdateScenarioAsync(Scenario scenario);
|
||||||
Task UpdateStrategyAsync(IndicatorBase indicatorBase);
|
Task UpdateStrategyAsync(IndicatorBase indicatorBase);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public interface ITradingService
|
|||||||
Task UpdateScenarioAsync(Scenario scenario);
|
Task UpdateScenarioAsync(Scenario scenario);
|
||||||
Task UpdateIndicatorAsync(IndicatorBase indicatorBase);
|
Task UpdateIndicatorAsync(IndicatorBase indicatorBase);
|
||||||
Task<IEnumerable<Position>> GetBrokerPositions(Account account);
|
Task<IEnumerable<Position>> GetBrokerPositions(Account account);
|
||||||
|
Task<IEnumerable<Position>> GetAllDatabasePositionsAsync();
|
||||||
Task<PrivyInitAddressResponse> InitPrivyWallet(string publicAddress);
|
Task<PrivyInitAddressResponse> InitPrivyWallet(string publicAddress);
|
||||||
|
|
||||||
// Synth API integration methods
|
// Synth API integration methods
|
||||||
|
|||||||
@@ -75,14 +75,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Refreshing platform summary data");
|
_logger.LogInformation("Refreshing platform summary data");
|
||||||
|
|
||||||
// Get all data in parallel for better performance
|
var agents = await _agentService.GetAllAgentSummaries();
|
||||||
var agentsTask = _agentService.GetAllAgentSummaries();
|
var strategies = await _botService.GetBotsAsync();
|
||||||
var strategiesTask = _botService.GetBotsAsync();
|
|
||||||
|
|
||||||
await Task.WhenAll(agentsTask, strategiesTask);
|
|
||||||
|
|
||||||
var agents = await agentsTask;
|
|
||||||
var strategies = await strategiesTask;
|
|
||||||
|
|
||||||
// Calculate totals
|
// Calculate totals
|
||||||
var totalAgents = agents.Count();
|
var totalAgents = agents.Count();
|
||||||
@@ -183,19 +177,20 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get all open positions from all accounts
|
// Get all open positions from all accounts
|
||||||
var openPositions = await _tradingService.GetBrokerPositions(null);
|
// Get positions directly from database instead of exchange
|
||||||
|
var allPositions = await _tradingService.GetAllDatabasePositionsAsync();
|
||||||
|
var openPositions = allPositions?.Where(p => !p.IsFinished());
|
||||||
|
|
||||||
if (openPositions?.Any() == true)
|
if (openPositions?.Any() == true)
|
||||||
{
|
{
|
||||||
var positionCount = openPositions.Count();
|
var positionCount = openPositions.Count();
|
||||||
|
|
||||||
// Calculate open interest as the sum of position notional values
|
// Calculate open interest as the sum of leveraged position notional values
|
||||||
// Open interest = sum of (position size * price) for all open positions
|
// Open interest = sum of (position size * price * leverage) for all open positions
|
||||||
var openInterest = openPositions
|
var openInterest = openPositions
|
||||||
.Where(p => p.Open?.Price > 0 && p.Open?.Quantity > 0)
|
.Sum(p => (p.Open.Price * p.Open.Quantity) * p.Open.Leverage);
|
||||||
.Sum(p => p.Open.Price * p.Open.Quantity);
|
|
||||||
|
|
||||||
_logger.LogDebug("Calculated position metrics: {PositionCount} positions, {OpenInterest} open interest",
|
_logger.LogDebug("Calculated position metrics: {PositionCount} positions, {OpenInterest} leveraged open interest",
|
||||||
positionCount, openInterest);
|
positionCount, openInterest);
|
||||||
|
|
||||||
return (openInterest, positionCount);
|
return (openInterest, positionCount);
|
||||||
|
|||||||
@@ -250,6 +250,11 @@ public class TradingService : ITradingService
|
|||||||
return await _exchangeService.GetBrokerPositions(account);
|
return await _exchangeService.GetBrokerPositions(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Position>> GetAllDatabasePositionsAsync()
|
||||||
|
{
|
||||||
|
return await _tradingRepository.GetAllPositionsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ManageTrader(TraderFollowup a, List<Ticker> tickers)
|
private async Task ManageTrader(TraderFollowup a, List<Ticker> tickers)
|
||||||
{
|
{
|
||||||
var shortAddress = a.Account.Address.Substring(0, 6);
|
var shortAddress = a.Account.Address.Substring(0, 6);
|
||||||
|
|||||||
@@ -397,6 +397,21 @@ public class PostgreSqlTradingRepository : ITradingRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Position>> GetAllPositionsAsync()
|
||||||
|
{
|
||||||
|
var positions = await _context.Positions
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(p => p.User)
|
||||||
|
.Include(p => p.OpenTrade)
|
||||||
|
.Include(p => p.StopLossTrade)
|
||||||
|
.Include(p => p.TakeProfit1Trade)
|
||||||
|
.Include(p => p.TakeProfit2Trade)
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return PostgreSqlMappers.Map(positions);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Signal Methods
|
#region Signal Methods
|
||||||
|
|||||||
@@ -94,15 +94,15 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
function getToggleBotStatusBadge(status: string, identifier: string) {
|
function getToggleBotStatusBadge(status: BotStatus, identifier: string) {
|
||||||
const classes =
|
const classes =
|
||||||
baseBadgeClass() + (status == 'Up' ? ' bg-error' : ' bg-success')
|
baseBadgeClass() + (status == BotStatus.Running ? ' bg-error' : ' bg-success')
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={classes}
|
className={classes}
|
||||||
onClick={() => toggleBotStatus(status, identifier)}
|
onClick={() => toggleBotStatus(status, identifier)}
|
||||||
>
|
>
|
||||||
{status == 'Up' ? (
|
{status == BotStatus.Running ? (
|
||||||
<p className="text-accent-content flex">
|
<p className="text-accent-content flex">
|
||||||
<StopIcon width={15}></StopIcon>
|
<StopIcon width={15}></StopIcon>
|
||||||
</p>
|
</p>
|
||||||
@@ -165,11 +165,11 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
setShowTradesModal(true)
|
setShowTradesModal(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleBotStatus(status: string, identifier: string) {
|
function toggleBotStatus(status: BotStatus, identifier: string) {
|
||||||
const isUp = status == 'Up'
|
const isUp = status == BotStatus.Running
|
||||||
const t = new Toast(isUp ? 'Stoping bot' : 'Restarting bot')
|
const t = new Toast(isUp ? 'Stoping bot' : 'Restarting bot')
|
||||||
|
|
||||||
if (status == 'Up') {
|
if (status == BotStatus.Running) {
|
||||||
client
|
client
|
||||||
.bot_Stop(identifier)
|
.bot_Stop(identifier)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -178,7 +178,7 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
t.update('error', err)
|
t.update('error', err)
|
||||||
})
|
})
|
||||||
} else if (status == 'Down' || status == 'None') {
|
} else if (status == BotStatus.Stopped || status == BotStatus.Saved) {
|
||||||
client
|
client
|
||||||
.bot_Restart(identifier)
|
.bot_Restart(identifier)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -261,7 +261,7 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
{/* Action Badges - Only show for bot owners */}
|
{/* Action Badges - Only show for bot owners */}
|
||||||
{isBotOwner(bot.agentName) && (
|
{isBotOwner(bot.agentName) && (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{getToggleBotStatusBadge(bot.status, bot.identifier)}
|
{getToggleBotStatusBadge(bot.status as BotStatus, bot.identifier)}
|
||||||
{getUpdateBotBadge(bot)}
|
{getUpdateBotBadge(bot)}
|
||||||
{getManualPositionBadge(bot.identifier)}
|
{getManualPositionBadge(bot.identifier)}
|
||||||
{getDeleteBadge(bot.identifier)}
|
{getDeleteBadge(bot.identifier)}
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import React, {useEffect, useState} from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {
|
import {DataClient, type PlatformSummaryViewModel, type TopStrategiesViewModel} from '../../generated/ManagingApi'
|
||||||
DataClient,
|
|
||||||
type PlatformSummaryViewModel,
|
|
||||||
type StrategiesStatisticsViewModel,
|
|
||||||
type TopStrategiesViewModel
|
|
||||||
} from '../../generated/ManagingApi'
|
|
||||||
|
|
||||||
function PlatformSummary({ index }: { index: number }) {
|
function PlatformSummary({ index }: { index: number }) {
|
||||||
const { apiUrl } = useApiUrlStore()
|
const { apiUrl } = useApiUrlStore()
|
||||||
const [platformData, setPlatformData] = useState<PlatformSummaryViewModel | null>(null)
|
const [platformData, setPlatformData] = useState<PlatformSummaryViewModel | null>(null)
|
||||||
const [strategiesStats, setStrategiesStats] = useState<StrategiesStatisticsViewModel | null>(null)
|
|
||||||
const [topStrategies, setTopStrategies] = useState<TopStrategiesViewModel | null>(null)
|
const [topStrategies, setTopStrategies] = useState<TopStrategiesViewModel | null>(null)
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
@@ -23,14 +18,12 @@ function PlatformSummary({ index }: { index: number }) {
|
|||||||
const client = new DataClient({}, apiUrl)
|
const client = new DataClient({}, apiUrl)
|
||||||
|
|
||||||
// Fetch all platform data in parallel
|
// Fetch all platform data in parallel
|
||||||
const [platform, strategies, top] = await Promise.all([
|
const [platform, top] = await Promise.all([
|
||||||
client.data_GetPlatformSummary(),
|
client.data_GetPlatformSummary(),
|
||||||
client.data_GetStrategiesStatistics(),
|
|
||||||
client.data_GetTopStrategies()
|
client.data_GetTopStrategies()
|
||||||
])
|
])
|
||||||
|
|
||||||
setPlatformData(platform)
|
setPlatformData(platform)
|
||||||
setStrategiesStats(strategies)
|
|
||||||
setTopStrategies(top)
|
setTopStrategies(top)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError('Failed to fetch platform data')
|
setError('Failed to fetch platform data')
|
||||||
@@ -112,10 +105,10 @@ function PlatformSummary({ index }: { index: number }) {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h1 className="text-4xl font-bold text-white mb-2">
|
<h1 className="text-4xl font-bold text-white mb-2">
|
||||||
{formatNumber(strategiesStats?.totalStrategiesRunning || 0)} Strategies Deployed
|
{formatNumber(platformData?.totalActiveStrategies || 0)} Strategies Deployed
|
||||||
</h1>
|
</h1>
|
||||||
<div className="text-lg">
|
<div className="text-lg">
|
||||||
{strategiesStats && formatChangeIndicator(strategiesStats.changeInLast24Hours || 0)}
|
{platformData && formatChangeIndicator(platformData.strategiesChange24h || 0)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user