261 lines
9.4 KiB
C#
261 lines
9.4 KiB
C#
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using Alpaca.Markets;
|
|
using DesktopBot.Services;
|
|
|
|
namespace DesktopBot.ViewModels
|
|
{
|
|
// ─── BalanceViewModel ────────────────────────────────────────────────────────
|
|
|
|
public class BalanceViewModel : BaseViewModel
|
|
{
|
|
private readonly ITradingService _tradingService;
|
|
private bool _isLoading;
|
|
private string _errorMessage;
|
|
private bool _hasError;
|
|
|
|
public bool IsLoading
|
|
{
|
|
get => _isLoading;
|
|
set => SetProperty(ref _isLoading, value);
|
|
}
|
|
public string ErrorMessage
|
|
{
|
|
get => _errorMessage;
|
|
set => SetProperty(ref _errorMessage, value);
|
|
}
|
|
public bool HasError
|
|
{
|
|
get => _hasError;
|
|
set => SetProperty(ref _hasError, value);
|
|
}
|
|
|
|
public ObservableCollection<BalanceRowViewModel> BalanceRows { get; }
|
|
= new ObservableCollection<BalanceRowViewModel>();
|
|
|
|
public ICommand RefreshCommand { get; }
|
|
|
|
public BalanceViewModel(ITradingService tradingService)
|
|
{
|
|
_tradingService = tradingService;
|
|
RefreshCommand = new RelayCommand(async _ => await LoadAsync());
|
|
}
|
|
|
|
public async Task LoadAsync()
|
|
{
|
|
IsLoading = true;
|
|
HasError = false;
|
|
try
|
|
{
|
|
var account = await _tradingService.GetAccountAsync();
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
BalanceRows.Clear();
|
|
AddSection("Buying Power");
|
|
AddRow("RegT Buying Power", account.RegulationBuyingPower, account.RegulationBuyingPower);
|
|
AddRow("Day Trading Buying Power", account.DayTradingBuyingPower, account.DayTradingBuyingPower);
|
|
AddRow("Effective Buying Power", account.BuyingPower, account.BuyingPower);
|
|
AddRow("Non-Marginable Buying Power", account.NonMarginableBuyingPower, account.NonMarginableBuyingPower);
|
|
AddSection("Margin");
|
|
AddRow("Initial Margin", account.InitialMargin, account.InitialMargin);
|
|
AddRow("Maintenance Margin", account.MaintenanceMargin, account.MaintenanceMargin);
|
|
AddSection("Cash");
|
|
AddRow("Cash", account.TradableCash, account.TradableCash);
|
|
AddSection("Positions");
|
|
AddRow("Equity", account.LastEquity, account.Equity ?? 0m, bold: true);
|
|
AddRow("Long Market Value", account.LongMarketValue, account.LongMarketValue);
|
|
AddRow("Short Market Value", account.ShortMarketValue, account.ShortMarketValue);
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
HasError = true;
|
|
ErrorMessage = "Errore: " + ex.Message;
|
|
});
|
|
}
|
|
finally
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() => IsLoading = false);
|
|
}
|
|
}
|
|
|
|
private void AddSection(string title)
|
|
=> BalanceRows.Add(new BalanceRowViewModel { Label = title, IsSection = true });
|
|
private void AddRow(string label, decimal? last, decimal? curr, bool bold = false)
|
|
=> BalanceRows.Add(new BalanceRowViewModel
|
|
{
|
|
Label = label,
|
|
LastClose = last.HasValue ? "$" + last.Value.ToString("N2") : "-",
|
|
Current = curr.HasValue ? "$" + curr.Value.ToString("N2") : "-",
|
|
IsBold = bold
|
|
});
|
|
private void AddRow(string label, decimal last, decimal curr, bool bold = false)
|
|
=> BalanceRows.Add(new BalanceRowViewModel
|
|
{
|
|
Label = label,
|
|
LastClose = "$" + last.ToString("N2"),
|
|
Current = "$" + curr.ToString("N2"),
|
|
IsBold = bold
|
|
});
|
|
}
|
|
|
|
// ─── PositionsViewModel ──────────────────────────────────────────────────────
|
|
|
|
public class PositionsViewModel : BaseViewModel
|
|
{
|
|
private readonly ITradingService _tradingService;
|
|
private bool _isLoading;
|
|
private string _errorMessage;
|
|
private bool _hasError;
|
|
|
|
public bool IsLoading
|
|
{
|
|
get => _isLoading;
|
|
set => SetProperty(ref _isLoading, value);
|
|
}
|
|
public string ErrorMessage
|
|
{
|
|
get => _errorMessage;
|
|
set => SetProperty(ref _errorMessage, value);
|
|
}
|
|
public bool HasError
|
|
{
|
|
get => _hasError;
|
|
set => SetProperty(ref _hasError, value);
|
|
}
|
|
|
|
public ObservableCollection<PositionViewModel> Positions { get; }
|
|
= new ObservableCollection<PositionViewModel>();
|
|
|
|
public ICommand RefreshCommand { get; }
|
|
public ICommand CloseAllCommand { get; }
|
|
public ICommand ClosePositionCommand { get; }
|
|
|
|
public PositionsViewModel(ITradingService tradingService)
|
|
{
|
|
_tradingService = tradingService;
|
|
RefreshCommand = new RelayCommand(async _ => await LoadAsync());
|
|
CloseAllCommand = new RelayCommand(async _ =>
|
|
{
|
|
await _tradingService.CloseAllPositionsAsync();
|
|
await LoadAsync();
|
|
});
|
|
ClosePositionCommand = new RelayCommand(async p =>
|
|
{
|
|
if (p is string symbol)
|
|
{
|
|
await _tradingService.ClosePositionAsync(symbol);
|
|
await LoadAsync();
|
|
}
|
|
});
|
|
}
|
|
|
|
public async Task LoadAsync()
|
|
{
|
|
IsLoading = true;
|
|
HasError = false;
|
|
try
|
|
{
|
|
var positions = await _tradingService.GetAllPositionsAsync();
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
Positions.Clear();
|
|
foreach (var p in positions)
|
|
Positions.Add(new PositionViewModel(p));
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
HasError = true;
|
|
ErrorMessage = "Errore: " + ex.Message;
|
|
});
|
|
}
|
|
finally
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() => IsLoading = false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── OrdersViewModel ────────────────────────────────────────────────────────
|
|
|
|
public class OrdersViewModel : BaseViewModel
|
|
{
|
|
private readonly ITradingService _tradingService;
|
|
private bool _isLoading;
|
|
private string _errorMessage;
|
|
private bool _hasError;
|
|
|
|
public bool IsLoading
|
|
{
|
|
get => _isLoading;
|
|
set => SetProperty(ref _isLoading, value);
|
|
}
|
|
public string ErrorMessage
|
|
{
|
|
get => _errorMessage;
|
|
set => SetProperty(ref _errorMessage, value);
|
|
}
|
|
public bool HasError
|
|
{
|
|
get => _hasError;
|
|
set => SetProperty(ref _hasError, value);
|
|
}
|
|
|
|
public ObservableCollection<OrderViewModel> Orders { get; }
|
|
= new ObservableCollection<OrderViewModel>();
|
|
|
|
public ICommand RefreshCommand { get; }
|
|
public ICommand CancelOrderCommand { get; }
|
|
|
|
public OrdersViewModel(ITradingService tradingService)
|
|
{
|
|
_tradingService = tradingService;
|
|
RefreshCommand = new RelayCommand(async _ => await LoadAsync());
|
|
CancelOrderCommand = new RelayCommand(async p =>
|
|
{
|
|
if (p is Guid id)
|
|
{
|
|
await _tradingService.CancelOrderAsync(id);
|
|
await LoadAsync();
|
|
}
|
|
});
|
|
}
|
|
|
|
public async Task LoadAsync()
|
|
{
|
|
IsLoading = true;
|
|
HasError = false;
|
|
try
|
|
{
|
|
var orders = await _tradingService.GetOrdersAsync(OrderStatusFilter.All, 100);
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
Orders.Clear();
|
|
foreach (var o in orders)
|
|
Orders.Add(new OrderViewModel(o));
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
HasError = true;
|
|
ErrorMessage = "Errore: " + ex.Message;
|
|
});
|
|
}
|
|
finally
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() => IsLoading = false);
|
|
}
|
|
}
|
|
}
|
|
}
|