Add volumes and fix missing signal
This commit is contained in:
@@ -287,6 +287,53 @@ public class TradingBot : Bot, ITradingBot
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Signal> RecreateSignalFromPosition(Position position)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the candle that corresponds to the position opening time
|
||||
var positionCandle = OptimizedCandles.FirstOrDefault(c => c.Date <= position.Open.Date)
|
||||
?? OptimizedCandles.LastOrDefault();
|
||||
|
||||
if (positionCandle == null)
|
||||
{
|
||||
await LogWarning($"Cannot find candle for position {position.Identifier} opened at {position.Open.Date}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a new signal based on position information
|
||||
var recreatedSignal = new Signal(
|
||||
ticker: Config.Ticker,
|
||||
direction: position.OriginDirection,
|
||||
confidence: Confidence.Medium, // Default confidence for recreated signals
|
||||
candle: positionCandle,
|
||||
date: position.Open.Date,
|
||||
exchange: Account.Exchange,
|
||||
strategyType: StrategyType.Stc, // Use a valid strategy type for recreated signals
|
||||
signalType: SignalType.Signal
|
||||
);
|
||||
|
||||
// Since Signal identifier is auto-generated, we need to update our position
|
||||
// to use the new signal identifier, or find another approach
|
||||
// For now, let's update the position's SignalIdentifier to match the recreated signal
|
||||
position.SignalIdentifier = recreatedSignal.Identifier;
|
||||
|
||||
recreatedSignal.Status = SignalStatus.PositionOpen;
|
||||
recreatedSignal.User = Account.User;
|
||||
|
||||
// Add the recreated signal to our collection
|
||||
Signals.Add(recreatedSignal);
|
||||
|
||||
await LogInformation($"Successfully recreated signal {recreatedSignal.Identifier} for position {position.Identifier}");
|
||||
return recreatedSignal;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await LogWarning($"Error recreating signal for position {position.Identifier}: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ManagePositions()
|
||||
{
|
||||
// Update positions - iterate through positions instead of signals for better synchronization
|
||||
@@ -295,8 +342,16 @@ public class TradingBot : Bot, ITradingBot
|
||||
var signalForPosition = Signals.FirstOrDefault(s => s.Identifier == position.SignalIdentifier);
|
||||
if (signalForPosition == null)
|
||||
{
|
||||
await LogWarning($"Cannot find signal for position {position.Identifier}");
|
||||
continue;
|
||||
await LogInformation($"Signal not found for position {position.Identifier}. Recreating signal...");
|
||||
|
||||
// Recreate the signal based on position information
|
||||
signalForPosition = await RecreateSignalFromPosition(position);
|
||||
|
||||
if (signalForPosition == null)
|
||||
{
|
||||
await LogWarning($"Failed to recreate signal for position {position.Identifier}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure signal status is correctly set to PositionOpen if position is not finished
|
||||
|
||||
@@ -81,6 +81,45 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
|
||||
return averageHours.toFixed(2);
|
||||
};
|
||||
|
||||
// Calculate total volume traded with leverage
|
||||
const getTotalVolumeTraded = () => {
|
||||
let totalVolume = 0;
|
||||
|
||||
positions.forEach((position) => {
|
||||
// Calculate volume for open trade
|
||||
const openLeverage = position.open.leverage || 1;
|
||||
const openVolume = position.open.quantity * position.open.price * openLeverage;
|
||||
totalVolume += openVolume;
|
||||
|
||||
// Calculate volume for close trade (stopLoss or takeProfit based on realized P&L)
|
||||
if (position.profitAndLoss?.realized != null) {
|
||||
let closeTrade;
|
||||
if (position.profitAndLoss.realized > 0) {
|
||||
// Profitable close = Take Profit
|
||||
closeTrade = position.takeProfit1;
|
||||
} else {
|
||||
// Loss or breakeven close = Stop Loss
|
||||
closeTrade = position.stopLoss;
|
||||
}
|
||||
|
||||
if (closeTrade) {
|
||||
const closeLeverage = closeTrade.leverage || 1;
|
||||
const closeVolume = closeTrade.quantity * closeTrade.price * closeLeverage;
|
||||
totalVolume += closeVolume;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return totalVolume;
|
||||
};
|
||||
|
||||
// Calculate estimated UI fee (0.02% of total volume)
|
||||
const getEstimatedUIFee = () => {
|
||||
const totalVolume = getTotalVolumeTraded();
|
||||
const uiFeePercentage = 0.0002; // 0.02%
|
||||
return totalVolume * uiFeePercentage;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-flow-row">
|
||||
@@ -146,6 +185,20 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
|
||||
title="Avg Open Time (Losing)"
|
||||
content={getAverageOpenTimeLosing() + " hours"}
|
||||
></CardText>
|
||||
<CardText
|
||||
title="Volume Traded"
|
||||
content={"$" + getTotalVolumeTraded().toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
})}
|
||||
></CardText>
|
||||
<CardText
|
||||
title="Estimated UI Fee"
|
||||
content={"$" + getEstimatedUIFee().toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
})}
|
||||
></CardText>
|
||||
</div>
|
||||
<div>
|
||||
<figure>
|
||||
|
||||
Reference in New Issue
Block a user