Files
monisuo/flutter_monisuo/lib/providers/chart_provider.dart

219 lines
5.1 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter_chen_kchart/k_chart.dart';
import '../models/candle.dart';
/// 时间周期
enum ChartInterval {
min1('1分', '1m'),
min5('5分', '5m'),
min15('15分', '15m'),
hour1('1小时', '1h'),
hour4('4小时', '4h'),
day1('1天', '1d');
final String label;
final String value;
const ChartInterval(this.label, this.value);
}
/// 技术指标设置
class IndicatorSettings {
final bool showMA;
final bool showEMA;
final bool showBOLL;
final bool showVOL;
final bool showMACD;
final bool showKDJ;
final bool showRSI;
final bool showWR;
final bool showCCI;
const IndicatorSettings({
this.showMA = true,
this.showEMA = false,
this.showBOLL = false,
this.showVOL = true,
this.showMACD = true,
this.showKDJ = false,
this.showRSI = false,
this.showWR = false,
this.showCCI = false,
});
IndicatorSettings copyWith({
bool? showMA,
bool? showEMA,
bool? showBOLL,
bool? showVOL,
bool? showMACD,
bool? showKDJ,
bool? showRSI,
bool? showWR,
bool? showCCI,
}) {
return IndicatorSettings(
showMA: showMA ?? this.showMA,
showEMA: showEMA ?? this.showEMA,
showBOLL: showBOLL ?? this.showBOLL,
showVOL: showVOL ?? this.showVOL,
showMACD: showMACD ?? this.showMACD,
showKDJ: showKDJ ?? this.showKDJ,
showRSI: showRSI ?? this.showRSI,
showWR: showWR ?? this.showWR,
showCCI: showCCI ?? this.showCCI,
);
}
}
/// K 线数据 Provider
class ChartProvider extends ChangeNotifier {
// 当前币种
String _symbol = 'BTC';
String get symbol => _symbol;
// 时间周期
ChartInterval _interval = ChartInterval.hour1;
ChartInterval get interval => _interval;
// 技术指标
IndicatorSettings _indicators = const IndicatorSettings();
IndicatorSettings get indicators => _indicators;
// K 线数据(原始)
List<Candle> _candles = [];
List<Candle> get candles => _candles;
// k_chart 需要的数据格式
List<KLineEntity> get klineData {
return _candles.map((c) {
return KLineEntity.fromCustom(
open: c.open,
high: c.high,
low: c.low,
close: c.close,
vol: c.volume,
time: c.timestamp,
);
}).toList();
}
// 状态
bool _loading = false;
bool get loading => _loading;
String? _error;
String? get error => _error;
/// 切换币种
void setSymbol(String symbol) {
if (_symbol != symbol) {
_symbol = symbol;
loadCandles();
}
}
/// 切换时间周期
void setInterval(ChartInterval interval) {
if (_interval != interval) {
_interval = interval;
loadCandles(showLoading: false);
}
}
/// 更新指标设置
void updateIndicators(IndicatorSettings settings) {
_indicators = settings;
notifyListeners();
}
/// 加载 K 线数据
Future<void> loadCandles({bool showLoading = true}) async {
if (showLoading) {
_loading = true;
_error = null;
notifyListeners();
}
try {
// TODO: 对接真实 API
// 临时使用模拟数据
await Future.delayed(const Duration(milliseconds: 300));
_candles = _generateMockCandles();
if (showLoading) {
_loading = false;
notifyListeners();
} else {
notifyListeners();
}
} catch (e) {
if (showLoading) {
_loading = false;
}
_error = e.toString();
notifyListeners();
}
}
/// 生成模拟 K 线数据
List<Candle> _generateMockCandles() {
final now = DateTime.now();
final basePrice = _getBasePrice(_symbol);
final candles = <Candle>[];
for (int i = 100; i >= 0; i--) {
final time = now.subtract(Duration(
minutes: _interval == ChartInterval.min1
? i
: _interval == ChartInterval.min5
? i * 5
: _interval == ChartInterval.min15
? i * 15
: _interval == ChartInterval.hour1
? i * 60
: _interval == ChartInterval.hour4
? i * 240
: i * 1440,
));
final random = (i * 17) % 100 / 100;
final change = basePrice * 0.02 * (random - 0.5);
final open = basePrice + change;
final close = open + basePrice * 0.01 * ((i * 13) % 100 / 100 - 0.5);
final high = open > close ? open * 1.005 : close * 1.005;
final low = open < close ? open * 0.995 : close * 0.995;
final volume = 1000 + (i * 37) % 5000;
candles.add(Candle(
timestamp: time.millisecondsSinceEpoch,
open: open,
high: high,
low: low,
close: close,
volume: volume.toDouble(),
));
}
return candles;
}
double _getBasePrice(String symbol) {
switch (symbol.toUpperCase()) {
case 'BTC':
return 42000.0;
case 'ETH':
return 2200.0;
case 'BNB':
return 300.0;
case 'SOL':
return 100.0;
case 'XRP':
return 0.5;
case 'DOGE':
return 0.08;
default:
return 100.0;
}
}
}