| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- import 'package:dio/dio.dart';
- typedef PageResult = ({List<Map<String, dynamic>> items, bool hasMore});
- // type: 0=市价,1=限价,2=计划委托
- // direction: 0=做多,1=做空
- // 撤单传 entrustId(数字 ID)
- class FuturesService {
- const FuturesService(this._dio);
- final Dio _dio;
- static final _form = Options(
- contentType: 'application/x-www-form-urlencoded',
- );
- // ── 合约信息 ─────────────────────────────────────────────────
- Future<Map<String, dynamic>> getSymbolInfo(String symbol) async {
- final resp = await _dio.post<Map<String, dynamic>>(
- 'swap/symbol-info',
- data: {'symbol': symbol},
- options: _form,
- );
- final data = resp.data?['data'];
- if (data is Map<String, dynamic>) return data;
- return resp.data ?? {};
- }
- // ── 杠杆 ─────────────────────────────────────────────────────
- Future<int> getLeverage(int contractId) async {
- final resp = await _dio.post<Map<String, dynamic>>(
- 'swap/wallet-new/getLeverage',
- data: {'contractId': contractId},
- options: _form,
- );
- final data = resp.data?['data'];
- return (data is num ? data.toInt() : int.tryParse('$data')) ?? 20;
- }
- Future<void> modifyLeverage(int contractId, int leverage) async {
- await _dio.post<dynamic>(
- 'swap/wallet-new/modifyLeverage',
- data: {'contractId': contractId, 'leverage': leverage},
- options: _form,
- );
- }
- /// 切换仓位模式:0=合仓(全仓)1=分仓
- /// 后端要求有持仓/委托时禁止切换,失败会抛异常
- Future<void> modifyPositionType(int positionType) async {
- await _dio.post<dynamic>(
- 'swap/wallet-new/modifyType',
- data: {'positionType': positionType},
- options: _form,
- );
- }
- // ── 账户与仓位 ───────────────────────────────────────────────
- Future<Map<String, dynamic>> getWithPositions([String symbol = '']) async {
- final resp = await _dio.get<Map<String, dynamic>>(
- 'swap/wallet-new/get-with-positions',
- queryParameters: symbol.isNotEmpty ? {'symbol': symbol} : null,
- );
- return (resp.data?['data'] as Map<String, dynamic>?) ?? {};
- }
- // ── 委托单 ───────────────────────────────────────────────────
- Future<PageResult> getCurrentOrders({
- int pageNo = 1,
- int pageSize = 10,
- }) async {
- final resp = await _dio.get<Map<String, dynamic>>(
- 'swap/order/current',
- queryParameters: {'pageNo': pageNo, 'pageSize': pageSize},
- );
- return _extractPage(resp.data, pageSize);
- }
- static PageResult _extractPage(Map<String, dynamic>? body, int pageSize) {
- if (body == null) return (items: [], hasMore: false);
- List<Map<String, dynamic>> items = [];
- final direct = body['content'] ?? body['records'] ?? body['list'];
- if (direct is List) {
- items = direct.map((e) => Map<String, dynamic>.from(e as Map)).toList();
- final last = body['last'];
- final hasMore = last is bool ? !last : items.length >= pageSize;
- return (items: items, hasMore: hasMore);
- }
- final nested = body['data'];
- if (nested is Map) {
- final content = nested['content'] ?? nested['records'] ?? nested['list'];
- if (content is List) {
- items = content.map((e) => Map<String, dynamic>.from(e as Map)).toList();
- final last = nested['last'];
- final hasMore = last is bool ? !last : items.length >= pageSize;
- return (items: items, hasMore: hasMore);
- }
- }
- if (nested is List) {
- items = nested.map((e) => Map<String, dynamic>.from(e as Map)).toList();
- return (items: items, hasMore: items.length >= pageSize);
- }
- return (items: [], hasMore: false);
- }
- // ── 开仓 ─────────────────────────────────────────────────────
- Future<void> openOrder({
- required int contractCoinId,
- required int type,
- required int direction,
- required double volume,
- required int leverage,
- double? entrustPrice,
- double? triggerPrice,
- double? profitPrice,
- double? lossPrice,
- int? isPercentage, // 1=百分比模式
- int? positionType, // 0=全仓 1=分仓,由前端传递
- }) async {
- // 计划委托无 entrustPrice 时传 0(市价)
- final effectiveEntrustPrice = (type == 2 && (entrustPrice == null || entrustPrice <= 0))
- ? 0.0
- : entrustPrice;
- await _dio.post<dynamic>(
- 'swap/order/open/v3',
- data: {
- 'contractCoinId': contractCoinId,
- 'type': type,
- 'direction': direction,
- 'volume': volume.toString(),
- 'leverage': leverage,
- 'entrustPrice': effectiveEntrustPrice?.toString() ?? '',
- 'triggerPrice': triggerPrice?.toString() ?? '',
- 'profitPrice': profitPrice?.toString() ?? '',
- 'lossPrice': lossPrice?.toString() ?? '',
- if (isPercentage != null) 'isPercentage': isPercentage,
- if (positionType != null) 'positionType': positionType,
- },
- options: _form,
- );
- }
- // ── 平仓 ─────────────────────────────────────────────────────
- Future<void> closeMarket({
- required String positionId,
- required double volume,
- }) async {
- await _dio.post<dynamic>(
- 'swap/order/close',
- data: {
- 'positionId': positionId,
- 'volume': volume.toString(),
- 'type': 0,
- 'entrustPrice': '0',
- 'triggerPrice': '0',
- },
- options: _form,
- );
- }
- Future<void> closeLimit({
- required String positionId,
- required double price,
- required double volume,
- }) async {
- await _dio.post<dynamic>(
- 'swap/order/close',
- data: {
- 'positionId': positionId,
- 'entrustPrice': price.toString(),
- 'volume': volume.toString(),
- 'type': 1,
- 'triggerPrice': '0',
- },
- options: _form,
- );
- }
- Future<void> closeAllPositions() async {
- await _dio.post<dynamic>('swap/order/close-all-coins', options: _form);
- }
- // entrustPrice=0 → 计划市价;>0 → 计划限价
- Future<void> closeConditional({
- required String positionId,
- required double triggerPrice,
- required double volume,
- double entrustPrice = 0,
- }) async {
- await _dio.post<dynamic>(
- 'swap/order/close',
- data: {
- 'positionId': positionId,
- 'entrustPrice': entrustPrice.toString(),
- 'volume': volume.toString(),
- 'type': 2,
- 'triggerPrice': triggerPrice.toString(),
- },
- options: _form,
- );
- }
- Future<void> reverseOpenPosition(String positionId) async {
- await _dio.post<dynamic>(
- 'swap/order/close-and-open',
- data: {'positionId': positionId},
- options: _form,
- );
- }
- // ── 撤单 ─────────────────────────────────────────────────────
- Future<void> cancelOrder(int entrustId) async {
- await _dio.post<dynamic>(
- 'swap/order/cancel',
- data: {'entrustId': entrustId},
- options: _form,
- );
- }
- // entrustIds 以 JSON 数组字符串传递,如 "[1,2,3]"
- Future<void> cancelOrdersByIds(List<int> entrustIds) async {
- await _dio.post<dynamic>(
- 'swap/order/cancel-by-ids',
- data: {'entrustIds': entrustIds.toString()},
- options: _form,
- );
- }
- // ── 止盈止损 ─────────────────────────────────────────────────
- // 首次设置(无 cutEntrustId)
- Future<void> setTpsl({
- required String positionId,
- double? profitPrice,
- double? lossPrice,
- }) async {
- await _dio.post<dynamic>(
- 'swap/order/cut-position',
- data: {
- 'positionId': positionId,
- 'profitPrice': profitPrice?.toString() ?? '0',
- 'profitEntrustPrice': '0.0',
- 'lossPrice': lossPrice?.toString() ?? '0',
- 'lossEntrustPrice': '0.0',
- },
- options: _form,
- );
- }
- // 修改已有止盈止损委托(有 cutEntrustId)
- Future<void> modifyCutOrder({
- required int entrustId,
- double? profitPrice,
- double? lossPrice,
- }) async {
- await _dio.post<dynamic>(
- 'swap/order/modify-cut',
- data: {
- 'entrustId': entrustId,
- 'profitPrice': profitPrice?.toString() ?? '0',
- 'lossPrice': lossPrice?.toString() ?? '0',
- },
- options: _form,
- );
- }
- // ── 历史记录 ─────────────────────────────────────────────────
- Future<PageResult> getPositionHistory({
- int pageNo = 1,
- int pageSize = 10,
- }) async {
- final resp = await _dio.get<Map<String, dynamic>>(
- 'swap/position/history',
- queryParameters: {'pageNo': pageNo, 'pageSize': pageSize},
- );
- return _extractPage(resp.data, pageSize);
- }
- Future<PageResult> getOrderHistoryAll({
- int pageNo = 1,
- int pageSize = 10,
- }) async {
- final resp = await _dio.get<Map<String, dynamic>>(
- 'swap/order/history-all',
- queryParameters: {'pageNo': pageNo, 'pageSize': pageSize},
- );
- return _extractPage(resp.data, pageSize);
- }
- }
|