Enhance SpotBot logging and orphaned position handling
- Updated SpotBot to log detailed information when detecting small token balances, indicating potential gas reserves or dust. - Introduced a minimum threshold for orphaned positions, improving decision-making on whether to open new positions. - Enhanced logging for potential zombie positions, providing clearer warnings when token balances are missing. - Improved force close logging to clarify the status of remaining balances after attempts to clear them.
This commit is contained in:
@@ -180,13 +180,30 @@ public class SpotBot : TradingBotBase
|
|||||||
return false; // Don't allow opening new position until resolved
|
return false; // Don't allow opening new position until resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenBalance is { Value: > 1m })
|
if (tokenBalance is { Amount: > 0 })
|
||||||
{
|
{
|
||||||
// We have a token balance but no internal position - attempt to recover orphaned position
|
// Check if this is a meaningful balance or just gas reserves / dust
|
||||||
|
// Minimum threshold: $10 USD value to be considered an orphaned position
|
||||||
|
const decimal minOrphanedBalanceValue = 10m;
|
||||||
|
|
||||||
|
if (tokenBalance.Value < minOrphanedBalanceValue)
|
||||||
|
{
|
||||||
|
await LogDebugAsync(
|
||||||
|
$"ℹ️ Small Token Balance Detected (Likely Gas Reserve or Dust)\n" +
|
||||||
|
$"Ticker: {Config.Ticker}\n" +
|
||||||
|
$"Token balance: `{tokenBalance.Amount:F8}`\n" +
|
||||||
|
$"USD Value: `${tokenBalance.Value:F2}`\n" +
|
||||||
|
$"Below orphaned threshold of `${minOrphanedBalanceValue:F2}`\n" +
|
||||||
|
$"Ignoring - safe to open new position");
|
||||||
|
return true; // Safe to open new position - this is just dust/gas reserve
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a significant token balance but no internal position - attempt to recover orphaned position
|
||||||
await LogWarningAsync(
|
await LogWarningAsync(
|
||||||
$"⚠️ Orphaned Token Balance Detected\n" +
|
$"⚠️ Orphaned Token Balance Detected\n" +
|
||||||
$"Ticker: {Config.Ticker}\n" +
|
$"Ticker: {Config.Ticker}\n" +
|
||||||
$"Token balance: `{tokenBalance.Amount:F5}`\n" +
|
$"Token balance: `{tokenBalance.Amount:F5}` (Value: ${tokenBalance.Value:F2})\n" +
|
||||||
|
$"Above orphaned threshold of `${minOrphanedBalanceValue:F2}`\n" +
|
||||||
$"But no internal position tracked\n" +
|
$"But no internal position tracked\n" +
|
||||||
$"Attempting to recover position from database...");
|
$"Attempting to recover position from database...");
|
||||||
|
|
||||||
@@ -198,7 +215,7 @@ public class SpotBot : TradingBotBase
|
|||||||
$"Could not recover orphaned position\n" +
|
$"Could not recover orphaned position\n" +
|
||||||
$"Manual cleanup may be required");
|
$"Manual cleanup may be required");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // Don't allow opening new position until next cycle
|
return false; // Don't allow opening new position until next cycle
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,12 +430,17 @@ public class SpotBot : TradingBotBase
|
|||||||
|
|
||||||
// Update quantity to match actual token balance
|
// Update quantity to match actual token balance
|
||||||
var actualTokenBalance = tokenBalance.Amount;
|
var actualTokenBalance = tokenBalance.Amount;
|
||||||
if (Math.Abs(internalPosition.Open.Quantity - actualTokenBalance) > 0.0001m)
|
var quantityTolerance = internalPosition.Open.Quantity * 0.006m; // 0.6% tolerance for slippage
|
||||||
|
var quantityDifference = Math.Abs(internalPosition.Open.Quantity - actualTokenBalance);
|
||||||
|
|
||||||
|
if (quantityDifference > quantityTolerance)
|
||||||
{
|
{
|
||||||
await LogDebugAsync(
|
await LogDebugAsync(
|
||||||
$"🔄 Token Balance Mismatch\n" +
|
$"🔄 Token Balance Mismatch\n" +
|
||||||
$"Internal Quantity: `{internalPosition.Open.Quantity:F5}`\n" +
|
$"Internal Quantity: `{internalPosition.Open.Quantity:F5}`\n" +
|
||||||
$"Broker Balance: `{actualTokenBalance:F5}`\n" +
|
$"Broker Balance: `{actualTokenBalance:F5}`\n" +
|
||||||
|
$"Difference: `{quantityDifference:F5}`\n" +
|
||||||
|
$"Tolerance (0.6%): `{quantityTolerance:F5}`\n" +
|
||||||
$"Updating to match broker balance");
|
$"Updating to match broker balance");
|
||||||
internalPosition.Open.Quantity = actualTokenBalance;
|
internalPosition.Open.Quantity = actualTokenBalance;
|
||||||
positionForSignal.Open.Quantity = actualTokenBalance;
|
positionForSignal.Open.Quantity = actualTokenBalance;
|
||||||
@@ -478,10 +500,15 @@ public class SpotBot : TradingBotBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await LogDebugAsync(
|
// Position is Filled but no token balance and not found in history
|
||||||
$"⚠️ Position Status Check\n" +
|
// This could be a zombie position - check if token balance exists via direct exchange call
|
||||||
$"Internal position `{internalPosition.Identifier}` shows Filled\n" +
|
await LogWarningAsync(
|
||||||
$"But no token balance found on broker or in history\n" +
|
$"⚠️ Potential Zombie Position Detected\n" +
|
||||||
|
$"Position: `{internalPosition.Identifier}`\n" +
|
||||||
|
$"Status: Filled\n" +
|
||||||
|
$"Token balance: 0\n" +
|
||||||
|
$"Not found in exchange history\n" +
|
||||||
|
$"This position may have been closed externally or data is delayed\n" +
|
||||||
$"Will retry verification on next cycle");
|
$"Will retry verification on next cycle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1089,8 +1116,10 @@ public class SpotBot : TradingBotBase
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Prevent infinite retry loop - only attempt force close once
|
||||||
|
// The next bot cycle will handle verification
|
||||||
await LogInformationAsync(
|
await LogInformationAsync(
|
||||||
$"🔄 Force Closing Remaining Balance\n" +
|
$"🔄 Force Closing Remaining Balance (One-Time Attempt)\n" +
|
||||||
$"Position: `{position.Identifier}`\n" +
|
$"Position: `{position.Identifier}`\n" +
|
||||||
$"Ticker: {Config.Ticker}\n" +
|
$"Ticker: {Config.Ticker}\n" +
|
||||||
$"Remaining Balance: `{remainingBalance:F5}`");
|
$"Remaining Balance: `{remainingBalance:F5}`");
|
||||||
@@ -1127,7 +1156,7 @@ public class SpotBot : TradingBotBase
|
|||||||
$"Cleared Balance: `{remainingBalance:F5}`\n" +
|
$"Cleared Balance: `{remainingBalance:F5}`\n" +
|
||||||
$"Close Price: `${currentPrice:F2}`");
|
$"Close Price: `${currentPrice:F2}`");
|
||||||
|
|
||||||
// Verify one more time that balance is now cleared
|
// Verify one more time that balance is now cleared (without triggering another force close)
|
||||||
await Task.Delay(2000); // Wait for swap to complete
|
await Task.Delay(2000); // Wait for swap to complete
|
||||||
|
|
||||||
var finalBalance = await ServiceScopeHelpers.WithScopedService<IExchangeService, Balance?>(
|
var finalBalance = await ServiceScopeHelpers.WithScopedService<IExchangeService, Balance?>(
|
||||||
@@ -1137,15 +1166,16 @@ public class SpotBot : TradingBotBase
|
|||||||
if (finalBalance is { Amount: > 0.0001m })
|
if (finalBalance is { Amount: > 0.0001m })
|
||||||
{
|
{
|
||||||
await LogWarningAsync(
|
await LogWarningAsync(
|
||||||
$"⚠️ Balance Still Remaining After Retry\n" +
|
$"⚠️ Balance Still Remaining After Force Close Attempt\n" +
|
||||||
$"Position: `{position.Identifier}`\n" +
|
$"Position: `{position.Identifier}`\n" +
|
||||||
$"Remaining: `{finalBalance.Amount:F5}`\n" +
|
$"Remaining: `{finalBalance.Amount:F5}`\n" +
|
||||||
$"Manual intervention may be required");
|
$"This will be handled on the next bot cycle\n" +
|
||||||
|
$"Manual intervention may be required if issue persists");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await LogInformationAsync(
|
await LogInformationAsync(
|
||||||
$"✅ Balance Fully Cleared After Retry\n" +
|
$"✅ Balance Fully Cleared After Force Close\n" +
|
||||||
$"Position: `{position.Identifier}`\n" +
|
$"Position: `{position.Identifier}`\n" +
|
||||||
$"Final Balance: `{finalBalance?.Amount ?? 0:F5}`");
|
$"Final Balance: `{finalBalance?.Amount ?? 0:F5}`");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user