funding_rate_service.dart 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import 'package:dio/dio.dart';
  2. import 'package:flutter/foundation.dart';
  3. import '../../../core/network/api_response.dart';
  4. import '../models/market/funding_rate.dart';
  5. /// 资金费率接口
  6. class FundingRateService {
  7. const FundingRateService(this._dio);
  8. final Dio _dio;
  9. static bool _isNoData(DioException e) =>
  10. e.response?.statusCode == 404 || e.error is ApiException;
  11. /// 当前资金费率
  12. /// GET /swap/funding-rate/current?contractCoinId=1
  13. Future<FundingRateCurrent?> getCurrent(int contractCoinId) async {
  14. try {
  15. final response = await _dio.get<Map<String, dynamic>>(
  16. 'swap/funding-rate/current',
  17. queryParameters: {'contractCoinId': contractCoinId},
  18. );
  19. final data = response.data?['data'];
  20. if (data is Map<String, dynamic>) {
  21. return FundingRateCurrent.fromJson(data);
  22. }
  23. return null;
  24. } on DioException catch (e) {
  25. if (_isNoData(e)) {
  26. debugPrint('[FundingRate] getCurrent no-data: ${e.error}');
  27. return null;
  28. }
  29. rethrow;
  30. }
  31. }
  32. /// 拉取单页历史记录
  33. Future<List<FundingRateHistoryItem>> _fetchPage(
  34. int contractCoinId, int pageNo, int pageSize) async {
  35. final response = await _dio.get<Map<String, dynamic>>(
  36. 'swap/funding-rate/history',
  37. queryParameters: {
  38. 'contractCoinId': contractCoinId,
  39. 'pageNo': pageNo,
  40. 'pageSize': pageSize,
  41. },
  42. );
  43. final data = response.data?['data'] ?? response.data;
  44. List? raw;
  45. if (data is Map<String, dynamic>) {
  46. raw = data['content'] as List?;
  47. } else if (data is List) {
  48. raw = data;
  49. }
  50. return (raw ?? [])
  51. .whereType<Map<String, dynamic>>()
  52. .map((e) => FundingRateHistoryItem.fromJson(e))
  53. .toList();
  54. }
  55. /// 资金费率历史——多页拉取,直到覆盖最近 [days] 天或服务端无更多数据
  56. /// GET /swap/funding-rate/history?contractCoinId=1&pageNo=N&pageSize=N
  57. Future<List<FundingRateHistoryItem>> getHistory({
  58. required int contractCoinId,
  59. int pageSize = 20,
  60. int days = 7,
  61. }) async {
  62. try {
  63. final cutoff = DateTime.now().subtract(Duration(days: days));
  64. final result = <FundingRateHistoryItem>[];
  65. int pageNo = 1;
  66. // 最多拉 10 页,防止死循环
  67. const maxPages = 10;
  68. while (pageNo <= maxPages) {
  69. final page = await _fetchPage(contractCoinId, pageNo, pageSize);
  70. result.addAll(page);
  71. // 服务端返回不足一页 → 已无更多数据
  72. if (page.length < pageSize) break;
  73. // 最早一条已早于 cutoff → 足够了
  74. final oldest = page
  75. .map((e) => e.fundingTime)
  76. .reduce((a, b) => a.isBefore(b) ? a : b);
  77. if (oldest.isBefore(cutoff)) break;
  78. pageNo++;
  79. }
  80. return result;
  81. } on DioException catch (e) {
  82. if (_isNoData(e)) {
  83. debugPrint('[FundingRate] getHistory no-data: ${e.error}');
  84. return [];
  85. }
  86. rethrow;
  87. }
  88. }
  89. }