Price reminder and init approval
* Start price reminder grain * Add config and init grain at startup * Save init wallet when already init
This commit is contained in:
@@ -331,6 +331,41 @@ export class AccountClient extends AuthorizedApiBase {
|
||||
}
|
||||
return Promise.resolve<SwapInfos>(null as any);
|
||||
}
|
||||
|
||||
account_GetExchangeApprovalStatus(): Promise<ExchangeApprovalStatus[]> {
|
||||
let url_ = this.baseUrl + "/Account/exchange-approval-status";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||
return this.http.fetch(url_, transformedOptions_);
|
||||
}).then((_response: Response) => {
|
||||
return this.processAccount_GetExchangeApprovalStatus(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processAccount_GetExchangeApprovalStatus(response: Response): Promise<ExchangeApprovalStatus[]> {
|
||||
const status = response.status;
|
||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||
if (status === 200) {
|
||||
return response.text().then((_responseText) => {
|
||||
let result200: any = null;
|
||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ExchangeApprovalStatus[];
|
||||
return result200;
|
||||
});
|
||||
} else if (status !== 200 && status !== 204) {
|
||||
return response.text().then((_responseText) => {
|
||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||
});
|
||||
}
|
||||
return Promise.resolve<ExchangeApprovalStatus[]>(null as any);
|
||||
}
|
||||
}
|
||||
|
||||
export class BacktestClient extends AuthorizedApiBase {
|
||||
@@ -3535,6 +3570,7 @@ export interface Account {
|
||||
secret?: string | null;
|
||||
user?: User | null;
|
||||
balances?: Balance[] | null;
|
||||
isGmxInitialized?: boolean;
|
||||
isPrivyWallet?: boolean;
|
||||
}
|
||||
|
||||
@@ -3735,6 +3771,11 @@ export interface SendTokenRequest {
|
||||
chainId?: number | null;
|
||||
}
|
||||
|
||||
export interface ExchangeApprovalStatus {
|
||||
exchange?: TradingExchanges;
|
||||
isApproved?: boolean;
|
||||
}
|
||||
|
||||
export interface Backtest {
|
||||
id: string;
|
||||
finalPnl: number;
|
||||
@@ -3984,7 +4025,7 @@ export enum Confidence {
|
||||
|
||||
export interface Candle {
|
||||
exchange: TradingExchanges;
|
||||
ticker: string;
|
||||
ticker: Ticker;
|
||||
openTime: Date;
|
||||
date: Date;
|
||||
open: number;
|
||||
@@ -4073,7 +4114,7 @@ export interface TradingBotConfigRequest {
|
||||
botTradingBalance: number;
|
||||
name: string;
|
||||
flipPosition: boolean;
|
||||
cooldownPeriod?: number;
|
||||
cooldownPeriod?: number | null;
|
||||
maxLossStreak?: number;
|
||||
scenario?: ScenarioRequest | null;
|
||||
scenarioName?: string | null;
|
||||
@@ -4625,6 +4666,8 @@ export interface PrivyInitAddressResponse {
|
||||
orderVaultHash?: string | null;
|
||||
exchangeRouterHash?: string | null;
|
||||
error?: string | null;
|
||||
address?: string | null;
|
||||
isAlreadyInitialized?: boolean;
|
||||
}
|
||||
|
||||
export interface LoginRequest {
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface Account {
|
||||
secret?: string | null;
|
||||
user?: User | null;
|
||||
balances?: Balance[] | null;
|
||||
isGmxInitialized?: boolean;
|
||||
isPrivyWallet?: boolean;
|
||||
}
|
||||
|
||||
@@ -218,6 +219,11 @@ export interface SendTokenRequest {
|
||||
chainId?: number | null;
|
||||
}
|
||||
|
||||
export interface ExchangeApprovalStatus {
|
||||
exchange?: TradingExchanges;
|
||||
isApproved?: boolean;
|
||||
}
|
||||
|
||||
export interface Backtest {
|
||||
id: string;
|
||||
finalPnl: number;
|
||||
@@ -467,7 +473,7 @@ export enum Confidence {
|
||||
|
||||
export interface Candle {
|
||||
exchange: TradingExchanges;
|
||||
ticker: string;
|
||||
ticker: Ticker;
|
||||
openTime: Date;
|
||||
date: Date;
|
||||
open: number;
|
||||
@@ -556,7 +562,7 @@ export interface TradingBotConfigRequest {
|
||||
botTradingBalance: number;
|
||||
name: string;
|
||||
flipPosition: boolean;
|
||||
cooldownPeriod?: number;
|
||||
cooldownPeriod?: number | null;
|
||||
maxLossStreak?: number;
|
||||
scenario?: ScenarioRequest | null;
|
||||
scenarioName?: string | null;
|
||||
@@ -1108,6 +1114,8 @@ export interface PrivyInitAddressResponse {
|
||||
orderVaultHash?: string | null;
|
||||
exchangeRouterHash?: string | null;
|
||||
error?: string | null;
|
||||
address?: string | null;
|
||||
isAlreadyInitialized?: boolean;
|
||||
}
|
||||
|
||||
export interface LoginRequest {
|
||||
|
||||
@@ -2,12 +2,12 @@ import React, {useState} from 'react'
|
||||
import {Card, FormInput, GridTile} from '../../components/mollecules'
|
||||
import useApiUrlStore from '../../app/store/apiStore'
|
||||
import {
|
||||
type AgentBalanceHistory,
|
||||
BotStatus,
|
||||
DataClient,
|
||||
type Position,
|
||||
TradeDirection,
|
||||
type UserStrategyDetailsViewModel
|
||||
type AgentBalanceHistory,
|
||||
BotStatus,
|
||||
DataClient,
|
||||
type Position,
|
||||
TradeDirection,
|
||||
type UserStrategyDetailsViewModel
|
||||
} from '../../generated/ManagingApi'
|
||||
|
||||
interface AgentData {
|
||||
@@ -140,7 +140,7 @@ function AgentSearch({ index }: { index: number }) {
|
||||
totalWins,
|
||||
totalLosses,
|
||||
avgWinRate,
|
||||
activeStrategies: agentData.strategies.filter(s => s.state === 'RUNNING').length,
|
||||
activeStrategies: agentData.strategies.filter(s => s.state === BotStatus.Running).length,
|
||||
totalStrategies: agentData.strategies.length
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import React, {useState} from 'react'
|
||||
import {FiRefreshCw, FiSend} from 'react-icons/fi'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
|
||||
import {SelectColumnFilter, Table} from '../../../components/mollecules'
|
||||
import type {IAccountRowDetail} from '../../../global/type.tsx'
|
||||
import type {Account, Balance} from '../../../generated/ManagingApi'
|
||||
import {Ticker} from '../../../generated/ManagingApi'
|
||||
import {AccountClient, Ticker} from '../../../generated/ManagingApi'
|
||||
import useApiUrlStore from '../../../app/store/apiStore'
|
||||
import SwapModal from './SwapModal'
|
||||
import SendTokenModal from './SendTokenModal'
|
||||
|
||||
@@ -17,6 +19,21 @@ const AccountRowDetails: React.FC<IAccountRowDetailProps> = ({
|
||||
showTotal,
|
||||
account,
|
||||
}) => {
|
||||
const { apiUrl } = useApiUrlStore()
|
||||
const accountClient = new AccountClient({}, apiUrl)
|
||||
|
||||
// Fetch exchange approval status using TanStack Query
|
||||
const { data: exchangeApprovalStatus, isLoading: isLoadingApprovalStatus, error: approvalStatusError, refetch: refetchApprovalStatus } = useQuery({
|
||||
queryKey: ['exchangeApprovalStatus'],
|
||||
queryFn: async () => {
|
||||
return await accountClient.account_GetExchangeApprovalStatus()
|
||||
},
|
||||
staleTime: 60000, // Consider data fresh for 1 minute
|
||||
gcTime: 5 * 60 * 1000, // Keep in cache for 5 minutes
|
||||
retry: 2, // Retry failed requests up to 2 times
|
||||
enabled: !!apiUrl, // Only run query when apiUrl is available
|
||||
})
|
||||
|
||||
const [swapModalState, setSwapModalState] = useState<{
|
||||
isOpen: boolean
|
||||
fromTicker: Ticker | null
|
||||
@@ -164,6 +181,44 @@ const AccountRowDetails: React.FC<IAccountRowDetailProps> = ({
|
||||
showTotal={showTotal}
|
||||
showPagination={false}
|
||||
/>
|
||||
|
||||
{/* Exchange Approval Status */}
|
||||
<div className="mt-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="text-sm font-medium text-gray-700">Exchange Approval Status</h4>
|
||||
<button
|
||||
className={`btn btn-xs btn-ghost ${isLoadingApprovalStatus ? 'loading' : ''}`}
|
||||
onClick={() => refetchApprovalStatus()}
|
||||
disabled={isLoadingApprovalStatus}
|
||||
title="Refresh approval status"
|
||||
>
|
||||
{!isLoadingApprovalStatus && <FiRefreshCw className="h-3 w-3" />}
|
||||
{!isLoadingApprovalStatus && <span className="ml-1">Refresh</span>}
|
||||
</button>
|
||||
</div>
|
||||
{isLoadingApprovalStatus ? (
|
||||
<div className="text-sm text-gray-500">Loading approval status...</div>
|
||||
) : approvalStatusError ? (
|
||||
<div className="text-sm text-red-500">Error loading approval status</div>
|
||||
) : exchangeApprovalStatus && exchangeApprovalStatus.length > 0 ? (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{exchangeApprovalStatus.map((status) => (
|
||||
<div
|
||||
key={status.exchange}
|
||||
className={`badge ${
|
||||
status.isApproved
|
||||
? 'badge-success'
|
||||
: 'badge-outline'
|
||||
}`}
|
||||
>
|
||||
{status.exchange}: {status.isApproved ? 'Approved' : 'Not Approved'}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-sm text-gray-500">No exchange data available</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{swapModalState.isOpen && swapModalState.fromTicker && (
|
||||
<SwapModal
|
||||
|
||||
Reference in New Issue
Block a user