79 lines
3.2 KiB
Dart
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();
|
|
}
|
|
}
|