| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import 'package:dio/dio.dart';
- /// 现货 API 服务 — 对接 /spot/v1/... 接口体系
- ///
- /// 接口对照(全部带 spot/ 前缀):
- /// GET spot/v1/config/coin/list 已开启币种列表(含图标/精度)
- /// GET spot/v1/config/symbol/list 已开启交易对列表(含精度/手续费/最小量)
- /// GET spot/v1/account/asset/list 用户现货资产列表(含今日盈亏)
- /// GET spot/v1/account/transfer/symbols 可划转币种列表
- /// POST spot/v1/account/transfer 资金账户 ↔ 现货账户划转
- /// POST spot/v1/order/create 创建订单
- /// POST spot/v1/order/cancel 撤单
- /// POST spot/v1/order/current 当前委托
- /// POST spot/v1/order/history 历史委托
- /// POST spot/v1/order/trades 成交记录
- /// POST spot/v1/account_records 资金流水
- class SpotService {
- const SpotService(this._dio);
- final Dio _dio;
- // ── 配置 ────────────────────────────────────────────
- /// 获取已开启的现货币种列表(含图标/显示精度/标签)
- Future<List<Map<String, dynamic>>> getCoins() async {
- final resp =
- await _dio.get<Map<String, dynamic>>('spot/v1/config/coin/list');
- return _extractList(resp.data);
- }
- /// 获取已开启且已发布的交易对列表(含精度/手续费/最小下单量/排序权重)
- Future<List<Map<String, dynamic>>> getSymbols() async {
- final resp =
- await _dio.get<Map<String, dynamic>>('spot/v1/config/symbol/list');
- return _extractList(resp.data);
- }
- // ── 资产 ────────────────────────────────────────────
- /// 获取用户现货资产列表(含 totalAmount/todayPnl/todayPnlRate)
- ///
- /// [hideZero] 传 true 时服务端过滤 0 余额币种(对齐 Web hideZero 逻辑)
- Future<Map<String, dynamic>> getAssets({bool? hideZero}) async {
- final query = <String, dynamic>{};
- if (hideZero != null) {
- query['hideZero'] = hideZero;
- }
- final resp = await _dio.get<Map<String, dynamic>>(
- 'spot/v1/account/asset/list',
- queryParameters: query.isEmpty ? null : query,
- );
- final data = resp.data?['data'];
- if (data is Map<String, dynamic>) return data;
- return {};
- }
- /// 获取可划转的开放币种列表
- Future<List<Map<String, dynamic>>> getTransferSymbols() async {
- final resp = await _dio
- .get<Map<String, dynamic>>('spot/v1/account/transfer/symbols');
- return _extractList(resp.data);
- }
- /// 账户间划转:资金账户 ↔ 现货账户
- ///
- /// [direction] 1=资金账户→现货账户,2=现货账户→资金账户
- Future<void> transfer({
- required String symbol,
- required double amount,
- required int direction,
- }) async {
- await _dio.post<dynamic>(
- 'spot/v1/account/transfer',
- data: {'symbol': symbol, 'amount': amount, 'direction': direction},
- );
- }
- // ── 订单 ────────────────────────────────────────────
- /// 创建订单
- ///
- /// [type] 1=限价单,2=市价单
- /// [side] BUY / SELL
- /// [price] 限价单传价格;市价单传 0
- /// [volume] 限价单传基础币数量;市价买传 USDT 金额;市价卖传基础币数量
- Future<Map<String, dynamic>> placeOrder({
- required String symbol,
- required String side,
- required int type,
- required double price,
- required double volume,
- }) async {
- final resp = await _dio.post<Map<String, dynamic>>(
- 'spot/v1/order/create',
- data: {
- 'symbol': symbol,
- 'side': side,
- 'type': type,
- 'price': price,
- 'volume': volume,
- 'source': 2,
- 'orderType': 1,
- },
- );
- final data = resp.data?['data'];
- if (data is Map<String, dynamic>) return data;
- return {};
- }
- /// 撤单
- Future<void> cancelOrder(int orderId) async {
- await _dio.post<dynamic>(
- 'spot/v1/order/cancel',
- data: {'orderId': orderId},
- );
- }
- /// 查询当前委托(未完成挂单)
- Future<Map<String, dynamic>> getCurrentOrders({
- String? symbol,
- String? side,
- int page = 1,
- int size = 50,
- int? ctimeBegin,
- int? ctimeEnd,
- }) async {
- final body = <String, dynamic>{'page': page, 'size': size};
- if (symbol != null && symbol.isNotEmpty) body['symbol'] = symbol;
- if (side != null && side.isNotEmpty) body['side'] = side;
- if (ctimeBegin != null) body['ctimeBegin'] = ctimeBegin;
- if (ctimeEnd != null) body['ctimeEnd'] = ctimeEnd;
- final resp = await _dio.post<Map<String, dynamic>>('spot/v1/order/current',
- data: body);
- return _extractPageData(resp.data);
- }
- /// 查询历史委托(已完成或已撤单)
- Future<Map<String, dynamic>> getHistoryOrders({
- String? symbol,
- String? side,
- int? type,
- int? status,
- int page = 1,
- int size = 20,
- int? ctimeBegin,
- int? ctimeEnd,
- }) async {
- final body = <String, dynamic>{'page': page, 'size': size};
- if (symbol != null && symbol.isNotEmpty) body['symbol'] = symbol;
- if (side != null && side.isNotEmpty) body['side'] = side;
- if (type != null) body['type'] = type;
- if (status != null) body['status'] = status;
- if (ctimeBegin != null) body['ctimeBegin'] = ctimeBegin;
- if (ctimeEnd != null) body['ctimeEnd'] = ctimeEnd;
- final resp = await _dio.post<Map<String, dynamic>>('spot/v1/order/history',
- data: body);
- return _extractPageData(resp.data);
- }
- /// 查询成交记录(有成交量的订单)
- Future<Map<String, dynamic>> getTrades({
- String? symbol,
- String? side,
- int? type,
- int? status,
- int page = 1,
- int size = 20,
- int? ctimeBegin,
- int? ctimeEnd,
- }) async {
- final body = <String, dynamic>{'page': page, 'size': size};
- if (symbol != null && symbol.isNotEmpty) body['symbol'] = symbol;
- if (side != null && side.isNotEmpty) body['side'] = side;
- if (type != null) body['type'] = type;
- if (status != null) body['status'] = status;
- if (ctimeBegin != null) body['ctimeBegin'] = ctimeBegin;
- if (ctimeEnd != null) body['ctimeEnd'] = ctimeEnd;
- final resp = await _dio.post<Map<String, dynamic>>('spot/v1/order/trades',
- data: body);
- return _extractPageData(resp.data);
- }
- // ── 资金流水 ─────────────────────────────────────────
- /// 分页查询资金流水
- ///
- /// [type] 流水类型:1=划转转入,2=划转转出,5=成交,12=手续费
- Future<Map<String, dynamic>> getAccountRecords({
- String? symbol,
- int? type,
- int page = 1,
- int size = 20,
- int? startTime,
- int? endTime,
- }) async {
- final body = <String, dynamic>{'page': page, 'size': size};
- if (symbol != null && symbol.isNotEmpty) body['symbol'] = symbol;
- if (type != null) body['type'] = type;
- if (startTime != null) body['startTime'] = startTime;
- if (endTime != null) body['endTime'] = endTime;
- final resp = await _dio
- .post<Map<String, dynamic>>('spot/v1/account_records', data: body);
- return _extractPageData(resp.data);
- }
- // ── 工具 ────────────────────────────────────────────
- static List<Map<String, dynamic>> _extractList(Map<String, dynamic>? body) {
- final raw = body?['data'];
- if (raw is List) return raw.whereType<Map<String, dynamic>>().toList();
- return [];
- }
- static Map<String, dynamic> _extractPageData(Map<String, dynamic>? body) {
- final raw = body?['data'];
- if (raw is Map<String, dynamic>) return raw;
- return {};
- }
- }
|