Update healthcheck and display pnl on trades
This commit is contained in:
@@ -109,6 +109,11 @@ namespace Managing.Api.HealthChecks
|
|||||||
gmxData["responseTimeMs"] = responseTimeElement.GetInt32();
|
gmxData["responseTimeMs"] = responseTimeElement.GetInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gmxDataElement.TryGetProperty("uiFeeFactor", out var uiFeeFactorElement))
|
||||||
|
{
|
||||||
|
gmxData["uiFeeFactor"] = uiFeeFactorElement.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
if (gmxDataElement.TryGetProperty("sampleMarkets", out var sampleMarketsElement))
|
if (gmxDataElement.TryGetProperty("sampleMarkets", out var sampleMarketsElement))
|
||||||
{
|
{
|
||||||
var sampleMarkets = new List<Dictionary<string, string>>();
|
var sampleMarkets = new List<Dictionary<string, string>>();
|
||||||
|
|||||||
@@ -347,6 +347,11 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
if (!IsForBacktest)
|
if (!IsForBacktest)
|
||||||
{
|
{
|
||||||
position = positionsExchange.FirstOrDefault(p => p.Ticker == Ticker);
|
position = positionsExchange.FirstOrDefault(p => p.Ticker == Ticker);
|
||||||
|
|
||||||
|
if (position != null)
|
||||||
|
{
|
||||||
|
UpdatePositionPnl(positionForSignal.Identifier, position.ProfitAndLoss.Realized);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position.Status == PositionStatus.New)
|
if (position.Status == PositionStatus.New)
|
||||||
@@ -411,8 +416,6 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
{
|
{
|
||||||
Logger.LogInformation(
|
Logger.LogInformation(
|
||||||
$"Position {signal.Identifier} don't need to be update. Position still opened");
|
$"Position {signal.Identifier} don't need to be update. Position still opened");
|
||||||
|
|
||||||
await SetPositionStatus(signal.Identifier, PositionStatus.Filled);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,10 +450,6 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
{
|
{
|
||||||
Logger.LogInformation(
|
Logger.LogInformation(
|
||||||
$"Position {signal.Identifier} don't need to be update. Position still opened");
|
$"Position {signal.Identifier} don't need to be update. Position still opened");
|
||||||
|
|
||||||
position.Status = PositionStatus.Filled;
|
|
||||||
|
|
||||||
await SetPositionStatus(signal.Identifier, PositionStatus.Filled);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,8 +467,8 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, ex.Message);
|
await LogWarning($"Cannot update position {positionForSignal.Identifier}: {ex.Message}");
|
||||||
//SentrySdk.CaptureException(ex);
|
SentrySdk.CaptureException(ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,6 +726,14 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
positionStatus == PositionStatus.Filled ? SignalStatus.PositionOpen : SignalStatus.Expired);
|
positionStatus == PositionStatus.Filled ? SignalStatus.PositionOpen : SignalStatus.Expired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdatePositionPnl(string identifier, decimal realized)
|
||||||
|
{
|
||||||
|
Positions.First(p => p.Identifier == identifier).ProfitAndLoss = new ProfitAndLoss()
|
||||||
|
{
|
||||||
|
Realized = realized
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus)
|
private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus)
|
||||||
{
|
{
|
||||||
if (Signals.Any(s => s.Identifier == signalIdentifier))
|
if (Signals.Any(s => s.Identifier == signalIdentifier))
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ using Managing.ABI.GmxV2.SyntheticsReader.ContractDefinition;
|
|||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
using Managing.Core;
|
using Managing.Core;
|
||||||
using Managing.Domain.Candles;
|
using Managing.Domain.Candles;
|
||||||
|
using Managing.Domain.MoneyManagements;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
|
using Managing.Domain.Users;
|
||||||
using Managing.Infrastructure.Evm.Models.Gmx.v2;
|
using Managing.Infrastructure.Evm.Models.Gmx.v2;
|
||||||
using Managing.Infrastructure.Evm.Models.Proxy;
|
using Managing.Infrastructure.Evm.Models.Proxy;
|
||||||
using Nethereum.Web3;
|
using Nethereum.Web3;
|
||||||
using Managing.Domain.MoneyManagements;
|
|
||||||
using Managing.Domain.Users;
|
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
namespace Managing.Infrastructure.Evm.Services.Gmx;
|
namespace Managing.Infrastructure.Evm.Services.Gmx;
|
||||||
|
|
||||||
internal static class GmxV2Mappers
|
internal static class GmxV2Mappers
|
||||||
{
|
{
|
||||||
public static Trade Map(GmxV2Position position, Enums.Ticker ticker)
|
public static Trade Map(GmxV2Position position, Ticker ticker)
|
||||||
{
|
{
|
||||||
var entryPrice = GmxV2Helpers.GetEntryPrice(position.SizeInUsd, position.SizeInTokens,
|
var entryPrice = GmxV2Helpers.GetEntryPrice(position.SizeInUsd, position.SizeInTokens,
|
||||||
position.TokenData.Decimals);
|
position.TokenData.Decimals);
|
||||||
@@ -24,9 +24,9 @@ internal static class GmxV2Mappers
|
|||||||
var collateralLeverage = CalculateCollateralAndLeverage(position.SizeInUsd, position.CollateralAmount);
|
var collateralLeverage = CalculateCollateralAndLeverage(position.SizeInUsd, position.CollateralAmount);
|
||||||
var trade = new Trade(
|
var trade = new Trade(
|
||||||
DateHelpers.GetFromUnixTimestamp((int)position.IncreasedAtTime),
|
DateHelpers.GetFromUnixTimestamp((int)position.IncreasedAtTime),
|
||||||
position.IsLong ? Enums.TradeDirection.Long : Enums.TradeDirection.Short,
|
position.IsLong ? TradeDirection.Long : TradeDirection.Short,
|
||||||
Enums.TradeStatus.Filled,
|
TradeStatus.Filled,
|
||||||
Enums.TradeType.Limit,
|
TradeType.Limit,
|
||||||
ticker,
|
ticker,
|
||||||
collateralLeverage.collateral / parsedEntryPrice,
|
collateralLeverage.collateral / parsedEntryPrice,
|
||||||
parsedEntryPrice,
|
parsedEntryPrice,
|
||||||
@@ -56,8 +56,8 @@ internal static class GmxV2Mappers
|
|||||||
|
|
||||||
var trade = new Trade(
|
var trade = new Trade(
|
||||||
order.Date,
|
order.Date,
|
||||||
order.IsLong ? Enums.TradeDirection.Long : Enums.TradeDirection.Short,
|
order.IsLong ? TradeDirection.Long : TradeDirection.Short,
|
||||||
Enums.TradeStatus.PendingOpen,
|
TradeStatus.PendingOpen,
|
||||||
GmxV2Helpers.GetTradeType(order.OrderType),
|
GmxV2Helpers.GetTradeType(order.OrderType),
|
||||||
ticker,
|
ticker,
|
||||||
Convert.ToDecimal(quantity),
|
Convert.ToDecimal(quantity),
|
||||||
@@ -111,7 +111,7 @@ internal static class GmxV2Mappers
|
|||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Candle Map(List<double> marketPrices, Enums.Ticker ticker, Enums.Timeframe timeframe, int timeBetween)
|
public static Candle Map(List<double> marketPrices, Ticker ticker, Timeframe timeframe, int timeBetween)
|
||||||
{
|
{
|
||||||
return new Candle()
|
return new Candle()
|
||||||
{
|
{
|
||||||
@@ -121,20 +121,20 @@ internal static class GmxV2Mappers
|
|||||||
High = Convert.ToDecimal(marketPrices[2]),
|
High = Convert.ToDecimal(marketPrices[2]),
|
||||||
Low = Convert.ToDecimal(marketPrices[3]),
|
Low = Convert.ToDecimal(marketPrices[3]),
|
||||||
Close = Convert.ToDecimal(marketPrices[4]),
|
Close = Convert.ToDecimal(marketPrices[4]),
|
||||||
Exchange = Enums.TradingExchanges.Evm,
|
Exchange = TradingExchanges.Evm,
|
||||||
Ticker = ticker.ToString(),
|
Ticker = ticker.ToString(),
|
||||||
Timeframe = timeframe
|
Timeframe = timeframe
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Enums.Ticker> Map(GmxV2TokenList tokenList)
|
public static List<Ticker> Map(GmxV2TokenList tokenList)
|
||||||
{
|
{
|
||||||
var tokens = new List<Enums.Ticker>();
|
var tokens = new List<Ticker>();
|
||||||
foreach (var t in tokenList.Tokens)
|
foreach (var t in tokenList.Tokens)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ticker = MiscExtensions.ParseEnum<Enums.Ticker>(t.Symbol);
|
var ticker = MiscExtensions.ParseEnum<Ticker>(t.Symbol);
|
||||||
tokens.Add(ticker);
|
tokens.Add(ticker);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -187,7 +187,7 @@ internal static class GmxV2Mappers
|
|||||||
|
|
||||||
position.ProfitAndLoss = new ProfitAndLoss()
|
position.ProfitAndLoss = new ProfitAndLoss()
|
||||||
{
|
{
|
||||||
Net = (decimal)gmxPosition.Pnl
|
Realized = (decimal)gmxPosition.Pnl
|
||||||
};
|
};
|
||||||
|
|
||||||
position.Status = MiscExtensions.ParseEnum<PositionStatus>(gmxPosition.Status);
|
position.Status = MiscExtensions.ParseEnum<PositionStatus>(gmxPosition.Status);
|
||||||
|
|||||||
@@ -131,11 +131,17 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
|||||||
const marketsInfo = await sdk.markets.getMarketsInfo();
|
const marketsInfo = await sdk.markets.getMarketsInfo();
|
||||||
const responseTime = Date.now() - startTime;
|
const responseTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
// Get the uiFeeFactor
|
||||||
|
const uiFeeFactor = await sdk.utils.getUiFeeFactor();
|
||||||
|
|
||||||
if (!marketsInfo.marketsInfoData || Object.keys(marketsInfo.marketsInfoData).length === 0) {
|
if (!marketsInfo.marketsInfoData || Object.keys(marketsInfo.marketsInfoData).length === 0) {
|
||||||
return {
|
return {
|
||||||
status: 'degraded',
|
status: 'degraded',
|
||||||
message: 'GMX SDK returned empty markets info data',
|
message: 'GMX SDK returned empty markets info data',
|
||||||
data: { responseTimeMs: responseTime }
|
data: {
|
||||||
|
responseTimeMs: responseTime,
|
||||||
|
uiFeeFactor: uiFeeFactor.toString()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +174,8 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
|||||||
message: 'ETH market not found in GMX markets data',
|
message: 'ETH market not found in GMX markets data',
|
||||||
data: {
|
data: {
|
||||||
availableMarkets: marketInfoDetails,
|
availableMarkets: marketInfoDetails,
|
||||||
responseTimeMs: responseTime
|
responseTimeMs: responseTime,
|
||||||
|
uiFeeFactor: uiFeeFactor.toString()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -179,7 +186,8 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
|||||||
data: {
|
data: {
|
||||||
marketCount: Object.keys(marketsInfo.marketsInfoData).length,
|
marketCount: Object.keys(marketsInfo.marketsInfoData).length,
|
||||||
responseTimeMs: responseTime,
|
responseTimeMs: responseTime,
|
||||||
sampleMarkets: marketInfoDetails.slice(0, 3) // Just include first 3 markets for brevity
|
sampleMarkets: marketInfoDetails.slice(0, 3), // Just include first 3 markets for brevity
|
||||||
|
uiFeeFactor: uiFeeFactor.toString()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ const HealthChecks: React.FC = () => {
|
|||||||
if (gmxData.data.responseTimeMs) {
|
if (gmxData.data.responseTimeMs) {
|
||||||
marketDetails['Response Time'] = `${gmxData.data.responseTimeMs}ms`;
|
marketDetails['Response Time'] = `${gmxData.data.responseTimeMs}ms`;
|
||||||
}
|
}
|
||||||
|
if (gmxData.data.uiFeeFactor) {
|
||||||
|
marketDetails['UI Fee Factor'] = gmxData.data.uiFeeFactor;
|
||||||
|
}
|
||||||
|
|
||||||
// Add sample markets info (just count for details section)
|
// Add sample markets info (just count for details section)
|
||||||
if (gmxData.data.sampleMarkets && Array.isArray(gmxData.data.sampleMarkets)) {
|
if (gmxData.data.sampleMarkets && Array.isArray(gmxData.data.sampleMarkets)) {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import {useState} from 'react'
|
import {useState} from 'react'
|
||||||
|
|
||||||
const FeeCalculator: React.FC = () => {
|
const FeeCalculator: React.FC = () => {
|
||||||
const [volumeUsd, setVolumeUsd] = useState<number>(1000000)
|
const [volumeUsd, setVolumeUsd] = useState<number>(1400000)
|
||||||
const [uiFeePercent, setUiFeePercent] = useState<number>(0.002)
|
const [uiFeePercent, setUiFeePercent] = useState<number>(0.02)
|
||||||
const [rebatePercent, setRebatePercent] = useState<number>(10)
|
const [rebatePercent, setRebatePercent] = useState<number>(20)
|
||||||
|
const [fundingFeeRate, setFundingFeeRate] = useState<number>(0.00371) // Based on example: ~0.065 USD for 1751 USD volume
|
||||||
|
|
||||||
// Based on the specific example: 10% rebate on $1751 = $0.0983
|
// Based on the specific example: 10% rebate on $1751 = $0.0983
|
||||||
// This means at 10% rebate, $1 of volume = $0.0000561393 rebated
|
// This means at 10% rebate, $1 of volume = $0.0000561393 rebated
|
||||||
@@ -18,32 +19,39 @@ const FeeCalculator: React.FC = () => {
|
|||||||
// For 10% rebate on $1751 resulting in $0.0983 rebate
|
// For 10% rebate on $1751 resulting in $0.0983 rebate
|
||||||
const dailyRebate = volumeUsd * BASE_REBATE_PER_DOLLAR * (rebatePercent / 10) // Normalize to 10% base
|
const dailyRebate = volumeUsd * BASE_REBATE_PER_DOLLAR * (rebatePercent / 10) // Normalize to 10% base
|
||||||
|
|
||||||
// Total revenue is UI fees plus rebates
|
// Calculate funding fees based on the provided example (0.065 USD for 1751 USD)
|
||||||
const dailyTotalRevenue = dailyUiFees + dailyRebate
|
const dailyFundingFees = volumeUsd * (fundingFeeRate / 100)
|
||||||
|
|
||||||
|
// Total revenue is UI fees + rebates + funding fees
|
||||||
|
const dailyTotalRevenue = dailyUiFees + dailyRebate + dailyFundingFees
|
||||||
|
|
||||||
return {
|
return {
|
||||||
daily: {
|
daily: {
|
||||||
volume: volumeUsd,
|
volume: volumeUsd,
|
||||||
uiFees: dailyUiFees,
|
uiFees: dailyUiFees,
|
||||||
rebate: dailyRebate,
|
rebate: dailyRebate,
|
||||||
|
fundingFees: dailyFundingFees,
|
||||||
totalRevenue: dailyTotalRevenue
|
totalRevenue: dailyTotalRevenue
|
||||||
},
|
},
|
||||||
weekly: {
|
weekly: {
|
||||||
volume: volumeUsd * 7,
|
volume: volumeUsd * 7,
|
||||||
uiFees: dailyUiFees * 7,
|
uiFees: dailyUiFees * 7,
|
||||||
rebate: dailyRebate * 7,
|
rebate: dailyRebate * 7,
|
||||||
|
fundingFees: dailyFundingFees * 7,
|
||||||
totalRevenue: dailyTotalRevenue * 7
|
totalRevenue: dailyTotalRevenue * 7
|
||||||
},
|
},
|
||||||
monthly: {
|
monthly: {
|
||||||
volume: volumeUsd * 30,
|
volume: volumeUsd * 30,
|
||||||
uiFees: dailyUiFees * 30,
|
uiFees: dailyUiFees * 30,
|
||||||
rebate: dailyRebate * 30,
|
rebate: dailyRebate * 30,
|
||||||
|
fundingFees: dailyFundingFees * 30,
|
||||||
totalRevenue: dailyTotalRevenue * 30
|
totalRevenue: dailyTotalRevenue * 30
|
||||||
},
|
},
|
||||||
yearly: {
|
yearly: {
|
||||||
volume: volumeUsd * 365,
|
volume: volumeUsd * 365,
|
||||||
uiFees: dailyUiFees * 365,
|
uiFees: dailyUiFees * 365,
|
||||||
rebate: dailyRebate * 365,
|
rebate: dailyRebate * 365,
|
||||||
|
fundingFees: dailyFundingFees * 365,
|
||||||
totalRevenue: dailyTotalRevenue * 365
|
totalRevenue: dailyTotalRevenue * 365
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,15 +59,16 @@ const FeeCalculator: React.FC = () => {
|
|||||||
|
|
||||||
const fees = calculateFees()
|
const fees = calculateFees()
|
||||||
|
|
||||||
// Test calculation: For $1751 with 10% rebate
|
// Test calculations
|
||||||
const testVolume = 1751
|
const testVolume = 1751
|
||||||
const testRebate = testVolume * BASE_REBATE_PER_DOLLAR * (rebatePercent / 10)
|
const testRebate = testVolume * BASE_REBATE_PER_DOLLAR * (rebatePercent / 10)
|
||||||
|
const testFundingFee = testVolume * (fundingFeeRate / 100)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container p-4">
|
<div className="container p-4">
|
||||||
<h2 className="text-2xl font-bold mb-4">Platform Revenue Calculator</h2>
|
<h2 className="text-2xl font-bold mb-4">Platform Revenue Calculator</h2>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<label className="label">
|
<label className="label">
|
||||||
<span className="label-text">Daily Volume (USD)</span>
|
<span className="label-text">Daily Volume (USD)</span>
|
||||||
@@ -98,6 +107,20 @@ const FeeCalculator: React.FC = () => {
|
|||||||
className="input input-bordered"
|
className="input input-bordered"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="form-control">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text">Funding Fee Rate (%)</span>
|
||||||
|
<span className="label-text-alt">Funding fees from agents</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={fundingFeeRate}
|
||||||
|
onChange={(e) => setFundingFeeRate(Number(e.target.value))}
|
||||||
|
className="input input-bordered"
|
||||||
|
step="0.0001"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
@@ -108,6 +131,7 @@ const FeeCalculator: React.FC = () => {
|
|||||||
<th>Volume (USD)</th>
|
<th>Volume (USD)</th>
|
||||||
<th>UI Fees (USD)</th>
|
<th>UI Fees (USD)</th>
|
||||||
<th>Rebates (USD)</th>
|
<th>Rebates (USD)</th>
|
||||||
|
<th>Funding Fees (USD)</th>
|
||||||
<th>Total Revenue (USD)</th>
|
<th>Total Revenue (USD)</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -117,6 +141,7 @@ const FeeCalculator: React.FC = () => {
|
|||||||
<td>${fees.daily.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
<td>${fees.daily.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
||||||
<td>${fees.daily.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td>${fees.daily.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td>${fees.daily.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
<td>${fees.daily.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
||||||
|
<td>${fees.daily.fundingFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td className="font-bold">${fees.daily.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td className="font-bold">${fees.daily.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -124,6 +149,7 @@ const FeeCalculator: React.FC = () => {
|
|||||||
<td>${fees.weekly.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
<td>${fees.weekly.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
||||||
<td>${fees.weekly.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td>${fees.weekly.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td>${fees.weekly.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
<td>${fees.weekly.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
||||||
|
<td>${fees.weekly.fundingFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td className="font-bold">${fees.weekly.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td className="font-bold">${fees.weekly.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -131,6 +157,7 @@ const FeeCalculator: React.FC = () => {
|
|||||||
<td>${fees.monthly.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
<td>${fees.monthly.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
||||||
<td>${fees.monthly.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td>${fees.monthly.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td>${fees.monthly.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
<td>${fees.monthly.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
||||||
|
<td>${fees.monthly.fundingFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td className="font-bold">${fees.monthly.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td className="font-bold">${fees.monthly.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -138,6 +165,7 @@ const FeeCalculator: React.FC = () => {
|
|||||||
<td>${fees.yearly.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
<td>${fees.yearly.volume.toLocaleString(undefined, {maximumFractionDigits: 0})}</td>
|
||||||
<td>${fees.yearly.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td>${fees.yearly.uiFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td>${fees.yearly.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
<td>${fees.yearly.rebate.toLocaleString(undefined, {minimumFractionDigits: 4, maximumFractionDigits: 4})}</td>
|
||||||
|
<td>${fees.yearly.fundingFees.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
<td className="font-bold">${fees.yearly.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
<td className="font-bold">${fees.yearly.totalRevenue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -145,8 +173,12 @@ const FeeCalculator: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="alert alert-info mt-4">
|
<div className="alert alert-info mt-4">
|
||||||
<div>
|
<div className="flex flex-col gap-1">
|
||||||
<span className="font-semibold">Verification:</span> For a volume of $1751 with 10% rebate, the calculated rebate is ${testRebate.toFixed(4)} USD
|
<div>
|
||||||
|
<span className="font-semibold">Verification:</span> For a volume of $1751:
|
||||||
|
</div>
|
||||||
|
<div className="pl-4">- With 10% rebate, the calculated rebate is ${testRebate.toFixed(4)} USD</div>
|
||||||
|
<div className="pl-4">- The funding fee is ${testFundingFee.toFixed(2)} USD</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -155,7 +187,8 @@ const FeeCalculator: React.FC = () => {
|
|||||||
<ul className="list-disc pl-5 space-y-2">
|
<ul className="list-disc pl-5 space-y-2">
|
||||||
<li><strong>UI Fee:</strong> Charged on top of the base fee for transactions. For position operations, it's a percentage of the increase/decrease size.</li>
|
<li><strong>UI Fee:</strong> Charged on top of the base fee for transactions. For position operations, it's a percentage of the increase/decrease size.</li>
|
||||||
<li><strong>Rebate:</strong> Based on a ratio where $1 of volume with a 10% rebate generates $0.0000561393 of rebate. The actual rebate scales with both volume and rebate percentage.</li>
|
<li><strong>Rebate:</strong> Based on a ratio where $1 of volume with a 10% rebate generates $0.0000561393 of rebate. The actual rebate scales with both volume and rebate percentage.</li>
|
||||||
<li><strong>Total Revenue:</strong> The combined income from both UI fees and rebates.</li>
|
<li><strong>Funding Fee:</strong> Fees generated by agents based on the trading volume. This is a percentage of the total volume.</li>
|
||||||
|
<li><strong>Total Revenue:</strong> The combined income from UI fees, rebates, and funding fees.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h4 className="text-md font-semibold mt-4 mb-2">Fee Details</h4>
|
<h4 className="text-md font-semibold mt-4 mb-2">Fee Details</h4>
|
||||||
@@ -164,7 +197,7 @@ const FeeCalculator: React.FC = () => {
|
|||||||
The uiFeeFactor is a percentage value over 10^30. For example, if the uiFeeFactor is 2 * 10^25, the percentage charged would be 0.002%.
|
The uiFeeFactor is a percentage value over 10^30. For example, if the uiFeeFactor is 2 * 10^25, the percentage charged would be 0.002%.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm mt-2">
|
<p className="text-sm mt-2">
|
||||||
Both UI fees and rebates contribute to the platform's revenue stream and can be used to cover on-chain transaction costs and other operational expenses.
|
Both UI fees, rebates, and funding fees contribute to the platform's revenue stream and can be used to cover on-chain transaction costs and other operational expenses.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user