Files
Finlytic/FinlyticApp/lib/features/bot/repositories/bot_repository.dart
T

79 lines
3.2 KiB
Dart

import 'dart:async';
import 'package:finlytic_app/core/network/api_client.dart';
import '../models/bot_models.dart';
class BotRepository {
final ApiClient apiClient;
const BotRepository({required this.apiClient});
Future<BotStatusModel> fetchStatus() async {
final response = await apiClient.get('/api/v1/bot/status');
if (response.statusCode == 200 && response.data != null) {
return BotStatusModel.fromJson(response.data);
}
throw Exception('Failed to fetch bot status');
}
Future<AccountSummaryModel> fetchSummary() async {
final response = await apiClient.get('/api/v1/bot/portfolio/summary');
if (response.statusCode == 200 && response.data != null) {
return AccountSummaryModel.fromJson(response.data);
}
throw Exception('Failed to fetch account summary');
}
Future<List<BotTradeOrderModel>> fetchActivePositions() async {
final response = await apiClient.get('/api/v1/bot/positions/active');
if (response.statusCode == 200 && response.data != null) {
final List<dynamic> list = response.data;
return list.map((json) => BotTradeOrderModel.fromJson(json)).toList();
}
return [];
}
Future<BotTradeOrderModel> executeProposal(String proposalId, {String? venue, double? quantity}) async {
final response = await apiClient.post('/api/v1/bot/orders/execute', data: {
'proposalId': proposalId,
if (venue != null) 'preferredVenue': venue,
if (quantity != null) 'customQuantity': quantity,
});
if (response.statusCode == 200 && response.data != null) {
return BotTradeOrderModel.fromJson(response.data);
}
throw Exception('Failed to execute bot proposal');
}
Future<PanicCloseResultModel> panicCloseAll() async {
final response = await apiClient.post('/api/v1/bot/orders/panic-close');
if (response.statusCode == 200 && response.data != null) {
return PanicCloseResultModel.fromJson(response.data);
}
// A non-200 (e.g. 503 when FinlyticBot is unreachable) must NOT be swallowed into a fake "0
// closed / 0 skipped" result for an emergency action - the caller needs to know the attempt did
// not even go through (Rules.md §4).
throw Exception('Failed to trigger panic close');
}
/// Updates FinlyticBot's dynamic settings. The backend now responds with the raw list of persisted
/// `DynamicSettingDto` entries (see FinlyticBackend BotController.UpdateBotSettings), not a BotStatusModel,
/// so the canonical status is re-fetched afterward instead of being reconstructed from that list.
Future<BotStatusModel> updateSettings({
bool? autoExecutionEnabled,
int? maxPositions,
double? riskPerTradePercent,
int? minCompositeScore,
}) async {
final response = await apiClient.post('/api/v1/bot/settings/update', data: {
if (autoExecutionEnabled != null) 'autoExecutionEnabled': autoExecutionEnabled,
if (maxPositions != null) 'maxPositions': maxPositions,
if (riskPerTradePercent != null) 'riskPerTradePercent': riskPerTradePercent,
if (minCompositeScore != null) 'minCompositeScore': minCompositeScore,
});
if (response.statusCode != 200) {
throw Exception('Failed to update bot settings');
}
return fetchStatus();
}
}