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()
|
private async Task ManagePositions()
|
||||||
{
|
{
|
||||||
// Update positions - iterate through positions instead of signals for better synchronization
|
// Update positions - iterate through positions instead of signals for better synchronization
|
||||||
@@ -295,9 +342,17 @@ public class TradingBot : Bot, ITradingBot
|
|||||||
var signalForPosition = Signals.FirstOrDefault(s => s.Identifier == position.SignalIdentifier);
|
var signalForPosition = Signals.FirstOrDefault(s => s.Identifier == position.SignalIdentifier);
|
||||||
if (signalForPosition == null)
|
if (signalForPosition == null)
|
||||||
{
|
{
|
||||||
await LogWarning($"Cannot find signal for position {position.Identifier}");
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure signal status is correctly set to PositionOpen if position is not finished
|
// Ensure signal status is correctly set to PositionOpen if position is not finished
|
||||||
if (signalForPosition.Status != SignalStatus.PositionOpen)
|
if (signalForPosition.Status != SignalStatus.PositionOpen)
|
||||||
|
|||||||
@@ -81,6 +81,45 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
|
|||||||
return averageHours.toFixed(2);
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="grid grid-flow-row">
|
<div className="grid grid-flow-row">
|
||||||
@@ -146,6 +185,20 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
|
|||||||
title="Avg Open Time (Losing)"
|
title="Avg Open Time (Losing)"
|
||||||
content={getAverageOpenTimeLosing() + " hours"}
|
content={getAverageOpenTimeLosing() + " hours"}
|
||||||
></CardText>
|
></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>
|
||||||
<div>
|
<div>
|
||||||
<figure>
|
<figure>
|
||||||
|
|||||||
Reference in New Issue
Block a user