Nuove: multi-strategy, indicatori avanzati, posizioni
- Sidebar portfolio con metriche dettagliate (Totale, Investito, Disponibile, P&L, ROI) e aggiornamento real-time - Sistema multi-strategia: 8 strategie assegnabili per asset, voting decisionale, pagina Trading Control - Nuova pagina Posizioni: gestione, chiusura manuale, P&L non realizzato, notifiche - Sistema indicatori tecnici: 7+ indicatori configurabili, segnali real-time, raccomandazioni, storico segnali - Refactoring TradingBotService per capitale, P&L, ROI, eventi - Nuovi modelli e servizi per strategie/indicatori, persistenza configurazioni - UI/UX: navigazione aggiornata, widget, modali, responsive - Aggiornamento README e CHANGELOG con tutte le novità
This commit is contained in:
220
TradingBot/Components/Shared/IndicatorsWidget.razor
Normal file
220
TradingBot/Components/Shared/IndicatorsWidget.razor
Normal file
@@ -0,0 +1,220 @@
|
||||
@using TradingBot.Services
|
||||
@using TradingBot.Models
|
||||
@inject IndicatorsService IndicatorsService
|
||||
@inject TradingBotService BotService
|
||||
@implements IDisposable
|
||||
|
||||
<div class="indicators-widget">
|
||||
<div class="widget-header">
|
||||
<h3>Indicatori Attivi</h3>
|
||||
<a href="/indicators" class="btn-link">
|
||||
Configura <span class="bi bi-arrow-right"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="indicators-grid">
|
||||
@foreach (var indicator in enabledIndicators.Take(6))
|
||||
{
|
||||
<div class="indicator-mini-card">
|
||||
<div class="indicator-mini-header">
|
||||
<span class="indicator-mini-name">@indicator.Name</span>
|
||||
<span class="indicator-mini-type">@indicator.Type</span>
|
||||
</div>
|
||||
|
||||
@if (topAssets.Any())
|
||||
{
|
||||
var symbol = topAssets.First();
|
||||
var status = IndicatorsService.GetIndicatorStatus(indicator.Id, symbol);
|
||||
|
||||
if (status != null)
|
||||
{
|
||||
<div class="indicator-mini-value">
|
||||
<span class="value-number">@status.CurrentValue.ToString("F2")</span>
|
||||
<span class="value-condition condition-@status.Condition.ToString().ToLower()">
|
||||
@status.Condition
|
||||
</span>
|
||||
</div>
|
||||
<div class="indicator-mini-recommendation">
|
||||
@status.Recommendation
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="indicator-mini-loading">Calcolo...</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="indicator-mini-empty">Nessun asset attivo</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (enabledIndicators.Count() > 6)
|
||||
{
|
||||
<div class="indicators-more">
|
||||
<a href="/indicators" class="btn-secondary btn-sm">
|
||||
Vedi tutti (@enabledIndicators.Count()) <span class="bi bi-arrow-right"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.indicators-widget {
|
||||
background: #1a1f3a;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid rgba(99, 102, 241, 0.2);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.widget-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.widget-header h3 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
color: #e2e8f0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: #6366f1;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.btn-link:hover {
|
||||
color: #8b5cf6;
|
||||
}
|
||||
|
||||
.indicators-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.indicator-mini-card {
|
||||
background: #0f1629;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(99, 102, 241, 0.1);
|
||||
}
|
||||
|
||||
.indicator-mini-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.indicator-mini-name {
|
||||
font-weight: 700;
|
||||
color: #e2e8f0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.indicator-mini-type {
|
||||
padding: 0.125rem 0.5rem;
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
border-radius: 0.25rem;
|
||||
color: #6366f1;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.indicator-mini-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.value-number {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: #e2e8f0;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.value-condition {
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.condition-overbought { background: rgba(239, 68, 68, 0.2); color: #ef4444; }
|
||||
.condition-oversold { background: rgba(16, 185, 129, 0.2); color: #10b981; }
|
||||
.condition-bullish { background: rgba(16, 185, 129, 0.2); color: #10b981; }
|
||||
.condition-bearish { background: rgba(239, 68, 68, 0.2); color: #ef4444; }
|
||||
.condition-neutral { background: rgba(100, 116, 139, 0.2); color: #94a3b8; }
|
||||
.condition-ranging { background: rgba(245, 158, 11, 0.2); color: #f59e0b; }
|
||||
.condition-trending { background: rgba(59, 130, 246, 0.2); color: #3b82f6; }
|
||||
|
||||
.indicator-mini-recommendation {
|
||||
color: #94a3b8;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.indicator-mini-loading,
|
||||
.indicator-mini-empty {
|
||||
color: #64748b;
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.indicators-more {
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private List<IndicatorConfig> enabledIndicators = new();
|
||||
private List<string> topAssets = new();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
LoadData();
|
||||
IndicatorsService.OnIndicatorsChanged += HandleUpdate;
|
||||
BotService.OnStatusChanged += HandleUpdate;
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
enabledIndicators = IndicatorsService.GetEnabledIndicators().ToList();
|
||||
topAssets = BotService.AssetConfigurations.Values
|
||||
.Where(c => c.IsEnabled)
|
||||
.OrderByDescending(c => c.CurrentBalance + (c.CurrentHoldings * (BotService.GetLatestPrice(c.Symbol)?.Price ?? 0)))
|
||||
.Select(c => c.Symbol)
|
||||
.Take(1)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void HandleUpdate()
|
||||
{
|
||||
LoadData();
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
IndicatorsService.OnIndicatorsChanged -= HandleUpdate;
|
||||
BotService.OnStatusChanged -= HandleUpdate;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user