market_ticker.dart 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /// 行情 Ticker 数据模型(不可变)
  2. /// 实现 == / hashCode 让 .select() 能正确判断单个 ticker 是否变化,
  3. /// 只有该 symbol 的价格/涨跌幅真正变了才触发对应行重建。
  4. class MarketTicker {
  5. final String symbol; // e.g. "BTCUSDT"
  6. final String baseAsset; // e.g. "BTC"
  7. final double lastPrice;
  8. final double change24h; // 24h 涨跌幅(百分比)
  9. final double volume24h; // 24h 成交额(USDT)
  10. final bool isFutures; // true = 永续合约,false = 现货
  11. final bool isHot; // 是否热门
  12. final String icon; // 币种图标 URL
  13. final int? pricePrecision; // 价格精度(小数位数),来自 coinScale
  14. final String? lastPriceStr; // WS 返回的原始价格字符串
  15. const MarketTicker({
  16. required this.symbol,
  17. required this.baseAsset,
  18. required this.lastPrice,
  19. required this.change24h,
  20. required this.volume24h,
  21. this.isFutures = true,
  22. this.isHot = false,
  23. this.icon = '',
  24. this.pricePrecision,
  25. this.lastPriceStr,
  26. });
  27. /// 从 /swap/coin/enabled-list 接口解析
  28. /// 接口字段: symbol("BTC/USDT"), coinSymbol("BTC"), baseSymbol("USDT"), isHot(1/0)
  29. /// 价格数据由 WebSocket 推送,初始为 0
  30. factory MarketTicker.fromJson(Map<String, dynamic> json) {
  31. // symbol 格式 "BTC/USDT" → 转为 "BTCUSDT"
  32. final rawSymbol = json['symbol'] as String? ?? '';
  33. final symbol = rawSymbol.replaceAll('/', '');
  34. final coinSymbol = json['coinSymbol'] as String? ?? '';
  35. final rawScale = (json['coinScale'] ?? json['minScale']) as num?;
  36. return MarketTicker(
  37. symbol: symbol,
  38. baseAsset: coinSymbol,
  39. lastPrice: 0,
  40. change24h: 0,
  41. volume24h: 0,
  42. isFutures: true,
  43. isHot: json['isHot'] == 1 || json['isHot'] == '1',
  44. icon: json['icon'] as String? ?? '',
  45. pricePrecision: rawScale?.toInt(),
  46. );
  47. }
  48. @override
  49. bool operator ==(Object other) =>
  50. identical(this, other) ||
  51. other is MarketTicker &&
  52. symbol == other.symbol &&
  53. baseAsset == other.baseAsset &&
  54. lastPrice == other.lastPrice &&
  55. change24h == other.change24h &&
  56. volume24h == other.volume24h &&
  57. isFutures == other.isFutures &&
  58. isHot == other.isHot &&
  59. icon == other.icon &&
  60. pricePrecision == other.pricePrecision &&
  61. lastPriceStr == other.lastPriceStr;
  62. @override
  63. int get hashCode =>
  64. Object.hash(symbol, baseAsset, lastPrice, change24h, volume24h, isFutures, isHot, icon, pricePrecision, lastPriceStr);
  65. MarketTicker copyWith({
  66. String? symbol,
  67. String? baseAsset,
  68. double? lastPrice,
  69. double? change24h,
  70. double? volume24h,
  71. bool? isFutures,
  72. bool? isHot,
  73. String? icon,
  74. int? pricePrecision,
  75. String? lastPriceStr,
  76. }) {
  77. return MarketTicker(
  78. symbol: symbol ?? this.symbol,
  79. baseAsset: baseAsset ?? this.baseAsset,
  80. lastPrice: lastPrice ?? this.lastPrice,
  81. change24h: change24h ?? this.change24h,
  82. volume24h: volume24h ?? this.volume24h,
  83. isFutures: isFutures ?? this.isFutures,
  84. isHot: isHot ?? this.isHot,
  85. icon: icon ?? this.icon,
  86. pricePrecision: pricePrecision ?? this.pricePrecision,
  87. lastPriceStr: lastPriceStr ?? this.lastPriceStr,
  88. );
  89. }
  90. }