import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../../domain/entities/kline.dart';
import 'kline_painter.dart';
import 'kline_indicator_painter.dart';
import 'kline_volume_painter.dart';
import 'kline_data_processor.dart';

/// K线图主组件
class KlineChartWidget extends StatefulWidget {
  final List<Kline> klines;
  final String currentPrice;
  final bool showVolume;
  final bool isFullScreen;
  final VoidCallback? onFullScreenToggle;
  final List<String> timeRanges;
  final int selectedTimeIndex;
  final Function(int)? onTimeRangeChanged;

  const KlineChartWidget({
    super.key,
    required this.klines,
    required this.currentPrice,
    this.showVolume = true,
    this.isFullScreen = false,
    this.onFullScreenToggle,
    this.timeRanges = const ['1分', '5分', '15分', '30分', '1时', '4时', '日'],
    this.selectedTimeIndex = 4,
    this.onTimeRangeChanged,
  });

  @override
  State<KlineChartWidget> createState() => _KlineChartWidgetState();
}

class _KlineChartWidgetState extends State<KlineChartWidget> {
  // 颜色定义
  static const Color _orange = Color(0xFFFF6B00);
  static const Color _green = Color(0xFF10B981);
  static const Color _red = Color(0xFFEF4444);
  static const Color _grayText = Color(0xFF6B7280);
  static const Color _borderGray = Color(0xFFE5E7EB);

  // 缩放和滑动状态 - 基于candleWidth的缩放模式（大厂标准做法）
  double _candleWidth = 8.0;  // 单根K线宽度（像素）
  double _prevCandleWidth = 8.0;
  double _scrollX = 0.0;  // 滚动偏移（像素）
  double _startScrollX = 0.0;
  Offset? _startFocalPoint;
  bool _isScaling = false;
  double _chartWidth = 0.0;  // 缓存图表宽度

  // K线宽度范围
  static const double _minCandleWidth = 3.0;
  static const double _maxCandleWidth = 30.0;

  // 指标选择
  int _selectedMainIndicator = 0; // 0: MA, 1: EMA, 2: BOLL
  int _selectedSubIndicator = 0; // 0: MACD, 1: KDJ, 2: RSI

  // 十字线
  bool _showCrossLine = false;
  int _crossLineIndex = -1;

  @override
  void initState() {
    super.initState();
    // 初始化偏移量到最右边（显示最新数据）
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _scrollToEnd();
    });
  }

  void _scrollToEnd() {
    if (widget.klines.isEmpty || _chartWidth == 0) return;
    // 滚动到最右边（显示最新数据）
    final totalWidth = widget.klines.length * _candleWidth;
    final maxScroll = math.max(0.0, totalWidth - _chartWidth);
    setState(() {
      _scrollX = maxScroll;
    });
  }

  @override
  void didUpdateWidget(KlineChartWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.klines.length != widget.klines.length) {
      _scrollToEnd();
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.isFullScreen) {
      return _buildFullScreenChart();
    }
    return _buildNormalChart();
  }

  Widget _buildNormalChart() {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
      ),
      child: Column(
        children: [
          // 顶部工具栏
          _buildToolbar(),
          // K线图区域
          _buildChartArea(height: 200),
          // 时间周期选择
          _buildTimeRangeSelector(),
        ],
      ),
    );
  }

  Widget _buildFullScreenChart() {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        leading: IconButton(
          icon: const Icon(Icons.close, color: Color(0xFF1F2937)),
          onPressed: widget.onFullScreenToggle,
        ),
        title: const Text(
          'K线图',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Color(0xFF1F2937),
          ),
        ),
        centerTitle: true,
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh, color: _orange),
            onPressed: () {
              setState(() {
                _candleWidth = 8.0;
                _scrollToEnd();
              });
            },
          ),
        ],
      ),
      body: SafeArea(
        child: Column(
          children: [
            // 指标选择器
            _buildIndicatorSelector(),
            // K线图区域（占据大部分空间）
            Expanded(child: _buildChartArea()),
            // 时间周期选择
            _buildTimeRangeSelector(),
            const SizedBox(height: 8),
          ],
        ),
      ),
    );
  }

  Widget _buildToolbar() {
    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 12, 8, 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          // 指标切换（简化版）
          Row(
            children: [
              _buildIndicatorChip('MA', _selectedMainIndicator == 0, () {
                setState(() => _selectedMainIndicator = 0);
              }),
              const SizedBox(width: 8),
              _buildIndicatorChip('MACD', _selectedSubIndicator == 0, () {
                setState(() => _selectedSubIndicator = 0);
              }),
              const SizedBox(width: 8),
              _buildIndicatorChip('KDJ', _selectedSubIndicator == 1, () {
                setState(() => _selectedSubIndicator = 1);
              }),
            ],
          ),
          // 全屏按钮
          IconButton(
            icon: Icon(
              widget.isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen,
              color: _orange,
              size: 24,
            ),
            onPressed: widget.onFullScreenToggle,
            padding: EdgeInsets.zero,
            constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
          ),
        ],
      ),
    );
  }

  Widget _buildIndicatorChip(String label, bool isSelected, VoidCallback onTap) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
        decoration: BoxDecoration(
          color: isSelected ? _orange.withOpacity(0.1) : Colors.transparent,
          borderRadius: BorderRadius.circular(4),
          border: Border.all(
            color: isSelected ? _orange : _borderGray,
          ),
        ),
        child: Text(
          label,
          style: TextStyle(
            fontSize: 11,
            fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
            color: isSelected ? _orange : _grayText,
          ),
        ),
      ),
    );
  }

  Widget _buildIndicatorSelector() {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      decoration: BoxDecoration(
        border: Border(bottom: BorderSide(color: _borderGray)),
      ),
      child: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Row(
          children: [
            const Text('主图:', style: TextStyle(fontSize: 12, color: _grayText)),
            const SizedBox(width: 8),
            _buildIndicatorChip('MA', _selectedMainIndicator == 0, () {
              setState(() => _selectedMainIndicator = 0);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('EMA', _selectedMainIndicator == 1, () {
              setState(() => _selectedMainIndicator = 1);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('BOLL', _selectedMainIndicator == 2, () {
              setState(() => _selectedMainIndicator = 2);
            }),
            const SizedBox(width: 16),
            const Text('副图:', style: TextStyle(fontSize: 12, color: _grayText)),
            const SizedBox(width: 8),
            _buildIndicatorChip('MACD', _selectedSubIndicator == 0, () {
              setState(() => _selectedSubIndicator = 0);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('KDJ', _selectedSubIndicator == 1, () {
              setState(() => _selectedSubIndicator = 1);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('RSI', _selectedSubIndicator == 2, () {
              setState(() => _selectedSubIndicator = 2);
            }),
          ],
        ),
      ),
    );
  }

  Widget _buildChartArea({double? height}) {
    return GestureDetector(
      onScaleStart: _onScaleStart,
      onScaleUpdate: _onScaleUpdate,
      onScaleEnd: _onScaleEnd,
      onLongPressStart: _onLongPressStart,
      onLongPressMoveUpdate: _onLongPressMoveUpdate,
      onLongPressEnd: _onLongPressEnd,
      child: Container(
        height: height,
        padding: const EdgeInsets.symmetric(horizontal: 8),
        child: LayoutBuilder(
          builder: (context, constraints) {
            final chartHeight = height ?? constraints.maxHeight;
            final chartWidth = constraints.maxWidth;

            // 缓存图表宽度用于滚动计算
            _chartWidth = chartWidth;

            if (widget.klines.isEmpty) {
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Icon(Icons.show_chart, size: 48, color: _grayText.withOpacity(0.5)),
                    const SizedBox(height: 8),
                    const Text('暂无K线数据', style: TextStyle(color: _grayText)),
                  ],
                ),
              );
            }

            // 计算可见数据（基于像素滚动）
            final visibleData = _getVisibleData(chartWidth);

            // 计算指标数据
            final processor = KlineDataProcessor(widget.klines);
            final maData = processor.calculateMA([5, 10, 20, 60]);
            final macdData = processor.calculateMACD();
            final kdjData = processor.calculateKDJ();
            final rsiData = processor.calculateRSI();
            final bollData = processor.calculateBOLL();
            final emaData = processor.calculateEMA([5, 10, 20]);

            // 计算各区域高度 - 全屏模式给主图更多空间
            final mainChartHeight = widget.showVolume
                ? (widget.isFullScreen ? chartHeight * 0.65 : chartHeight * 0.6)
                : (widget.isFullScreen ? chartHeight * 0.75 : chartHeight * 0.7);
            final volumeHeight = widget.showVolume
                ? (widget.isFullScreen ? chartHeight * 0.12 : chartHeight * 0.2)
                : 0.0;
            final indicatorHeight = widget.isFullScreen
                ? (widget.showVolume ? chartHeight * 0.23 : chartHeight * 0.25)
                : (widget.showVolume ? chartHeight * 0.2 : chartHeight * 0.3);

            return Column(
              children: [
                // 主图（K线 + MA/EMA/BOLL）
                SizedBox(
                  height: mainChartHeight,
                  child: Stack(
                    children: [
                      CustomPaint(
                        size: Size(chartWidth, mainChartHeight),
                        painter: KlinePainter(
                          klines: visibleData.klines,
                          maData: _selectedMainIndicator == 0 ? _getVisibleMAData(maData, visibleData.startIndex) : null,
                          emaData: _selectedMainIndicator == 1 ? _getVisibleMAData(emaData, visibleData.startIndex) : null,
                          bollData: _selectedMainIndicator == 2 ? _getVisibleBollData(bollData, visibleData.startIndex) : null,
                          crossLineIndex: _showCrossLine ? _crossLineIndex - visibleData.startIndex : -1,
                          candleWidth: visibleData.candleWidth,
                        ),
                      ),
                      // 十字线信息
                      if (_showCrossLine && _crossLineIndex >= 0 && _crossLineIndex < widget.klines.length)
                        _buildCrossLineInfo(visibleData),
                      // 当前价格标签
                      if (visibleData.klines.isNotEmpty)
                        Positioned(
                          right: 0,
                          top: _calcPriceY(
                            visibleData,
                            double.tryParse(widget.currentPrice) ?? 0,
                            mainChartHeight,
                          ),
                          child: Container(
                            padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
                            decoration: BoxDecoration(
                              color: _orange,
                              borderRadius: BorderRadius.circular(2),
                            ),
                            child: Text(
                              _formatPrice(double.tryParse(widget.currentPrice) ?? 0),
                              style: const TextStyle(fontSize: 9, color: Colors.white),
                            ),
                          ),
                        ),
                    ],
                  ),
                ),
                // 成交量图
                if (widget.showVolume)
                  SizedBox(
                    height: volumeHeight,
                    child: CustomPaint(
                      size: Size(chartWidth, volumeHeight),
                      painter: KlineVolumePainter(
                        klines: visibleData.klines,
                        crossLineIndex: _showCrossLine ? _crossLineIndex - visibleData.startIndex : -1,
                        candleWidth: visibleData.candleWidth,
                      ),
                    ),
                  ),
                // 副图指标（MACD/KDJ/RSI）
                SizedBox(
                  height: indicatorHeight,
                  child: CustomPaint(
                    size: Size(chartWidth, indicatorHeight),
                    painter: KlineIndicatorPainter(
                      indicatorType: _selectedSubIndicator,
                      macdData: _selectedSubIndicator == 0 ? _getVisibleMacdData(macdData, visibleData.startIndex) : null,
                      kdjData: _selectedSubIndicator == 1 ? _getVisibleKdjData(kdjData, visibleData.startIndex) : null,
                      rsiData: _selectedSubIndicator == 2 ? _getVisibleRsiData(rsiData, visibleData.startIndex) : null,
                      crossLineIndex: _showCrossLine ? _crossLineIndex - visibleData.startIndex : -1,
                      candleWidth: visibleData.candleWidth,
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ),
    );
  }

  Widget _buildTimeRangeSelector() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
      child: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Row(
          children: List.generate(widget.timeRanges.length, (index) {
            final isSelected = widget.selectedTimeIndex == index;
            return Padding(
              padding: const EdgeInsets.only(right: 8),
              child: GestureDetector(
                onTap: () => widget.onTimeRangeChanged?.call(index),
                child: Container(
                  padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
                  decoration: BoxDecoration(
                    color: isSelected ? _orange : Colors.white,
                    borderRadius: BorderRadius.circular(9999),
                    border: isSelected ? null : Border.all(color: _borderGray),
                  ),
                  child: Text(
                    widget.timeRanges[index],
                    style: TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.w500,
                      color: isSelected ? Colors.white : _grayText,
                    ),
                  ),
                ),
              ),
            );
          }),
        ),
      ),
    );
  }

  // 手势处理 - 大厂标准做法：基于像素的滚动和缩放
  void _onScaleStart(ScaleStartDetails details) {
    _prevCandleWidth = _candleWidth;
    _startScrollX = _scrollX;
    _startFocalPoint = details.focalPoint;
    // 检测是否为两指缩放（pointerCount > 1表示多指触摸）
    _isScaling = details.pointerCount > 1;
  }

  void _onScaleUpdate(ScaleUpdateDetails details) {
    setState(() {
      // 两指缩放：调整K线宽度，围绕焦点缩放
      if (_isScaling || (details.scale - 1.0).abs() > 0.01) {
        _isScaling = true;
        final newCandleWidth = (_prevCandleWidth * details.scale).clamp(_minCandleWidth, _maxCandleWidth);

        // 围绕焦点缩放：调整滚动位置以保持焦点处的K线位置不变
        if (_startFocalPoint != null && _chartWidth > 0) {
          final focalRatio = _startFocalPoint!.dx / _chartWidth;
          final oldFocalIndex = (_startScrollX + _startFocalPoint!.dx) / _prevCandleWidth;
          final newFocalX = oldFocalIndex * newCandleWidth;
          _scrollX = (newFocalX - focalRatio * _chartWidth).clamp(
            0.0,
            math.max(0.0, widget.klines.length * newCandleWidth - _chartWidth),
          );
        }

        _candleWidth = newCandleWidth;
      }

      // 单指平移（非缩放模式时）- 直接使用像素位移
      if (!_isScaling && _startFocalPoint != null) {
        final dx = details.focalPoint.dx - _startFocalPoint!.dx;
        final totalWidth = widget.klines.length * _candleWidth;
        final maxScroll = math.max(0.0, totalWidth - _chartWidth);
        _scrollX = (_startScrollX - dx).clamp(0.0, maxScroll);
      }
    });
  }

  void _onScaleEnd(ScaleEndDetails details) {
    _startFocalPoint = null;
    _isScaling = false;
  }

  void _onLongPressStart(LongPressStartDetails details) {
    _updateCrossLine(details.localPosition);
    HapticFeedback.mediumImpact();
  }

  void _onLongPressMoveUpdate(LongPressMoveUpdateDetails details) {
    _updateCrossLine(details.localPosition);
  }

  void _onLongPressEnd(LongPressEndDetails details) {
    setState(() {
      _showCrossLine = false;
      _crossLineIndex = -1;
    });
  }

  void _updateCrossLine(Offset position) {
    if (widget.klines.isEmpty || _chartWidth == 0) return;

    setState(() {
      _showCrossLine = true;

      // 计算对应的K线索引（基于像素位置）
      final absoluteX = _scrollX + position.dx;
      final index = (absoluteX / _candleWidth).floor().clamp(0, widget.klines.length - 1);
      _crossLineIndex = index;
    });
  }

  // 数据处理 - 基于像素滚动计算可见数据
  _VisibleData _getVisibleData(double chartWidth) {
    if (widget.klines.isEmpty || chartWidth == 0) {
      return _VisibleData(klines: [], startIndex: 0, candleWidth: _candleWidth);
    }

    // 根据滚动位置计算可见的K线范围
    final int startIndex = (_scrollX / _candleWidth).floor().clamp(0, widget.klines.length - 1);
    final int visibleCount = (chartWidth / _candleWidth).ceil() + 1;  // +1 确保边缘K线可见
    final int endIndex = math.min(startIndex + visibleCount, widget.klines.length);

    return _VisibleData(
      klines: widget.klines.sublist(startIndex, endIndex),
      startIndex: startIndex,
      candleWidth: _candleWidth,
    );
  }

  int _getVisibleCount() {
    if (_chartWidth == 0) return 60;
    return (_chartWidth / _candleWidth).ceil() + 1;
  }

  Map<int, List<double?>> _getVisibleMAData(Map<int, List<double?>> fullData, int startIndex) {
    final visibleCount = _getVisibleCount();
    final result = <int, List<double?>>{};
    for (final entry in fullData.entries) {
      final endIndex = math.min(startIndex + visibleCount, entry.value.length);
      if (startIndex < entry.value.length) {
        result[entry.key] = entry.value.sublist(startIndex, endIndex);
      }
    }
    return result;
  }

  Map<String, List<double?>> _getVisibleBollData(Map<String, List<double?>> fullData, int startIndex) {
    final visibleCount = _getVisibleCount();
    final result = <String, List<double?>>{};
    for (final entry in fullData.entries) {
      final endIndex = math.min(startIndex + visibleCount, entry.value.length);
      if (startIndex < entry.value.length) {
        result[entry.key] = entry.value.sublist(startIndex, endIndex);
      }
    }
    return result;
  }

  Map<String, List<double?>> _getVisibleMacdData(Map<String, List<double?>> fullData, int startIndex) {
    final visibleCount = _getVisibleCount();
    final result = <String, List<double?>>{};
    for (final entry in fullData.entries) {
      final endIndex = math.min(startIndex + visibleCount, entry.value.length);
      if (startIndex < entry.value.length) {
        result[entry.key] = entry.value.sublist(startIndex, endIndex);
      }
    }
    return result;
  }

  Map<String, List<double?>> _getVisibleKdjData(Map<String, List<double?>> fullData, int startIndex) {
    final visibleCount = _getVisibleCount();
    final result = <String, List<double?>>{};
    for (final entry in fullData.entries) {
      final endIndex = math.min(startIndex + visibleCount, entry.value.length);
      if (startIndex < entry.value.length) {
        result[entry.key] = entry.value.sublist(startIndex, endIndex);
      }
    }
    return result;
  }

  List<double?> _getVisibleRsiData(List<double?> fullData, int startIndex) {
    final visibleCount = _getVisibleCount();
    final endIndex = math.min(startIndex + visibleCount, fullData.length);
    if (startIndex < fullData.length) {
      return fullData.sublist(startIndex, endIndex);
    }
    return [];
  }

  Widget _buildCrossLineInfo(_VisibleData visibleData) {
    if (_crossLineIndex < 0 || _crossLineIndex >= widget.klines.length) {
      return const SizedBox.shrink();
    }

    final kline = widget.klines[_crossLineIndex];
    final open = double.tryParse(kline.open) ?? 0;
    final high = double.tryParse(kline.high) ?? 0;
    final low = double.tryParse(kline.low) ?? 0;
    final close = double.tryParse(kline.close) ?? 0;
    final volume = double.tryParse(kline.volume) ?? 0;
    final isUp = close >= open;

    return Positioned(
      left: 8,
      top: 8,
      child: Container(
        padding: const EdgeInsets.all(8),
        decoration: BoxDecoration(
          color: Colors.white.withOpacity(0.95),
          borderRadius: BorderRadius.circular(8),
          border: Border.all(color: _borderGray),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.1),
              blurRadius: 4,
            ),
          ],
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              _formatDateTime(kline.time),
              style: const TextStyle(fontSize: 10, color: _grayText),
            ),
            const SizedBox(height: 4),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                _buildInfoItem('开', _formatPrice(open), isUp ? _green : _red),
                const SizedBox(width: 12),
                _buildInfoItem('高', _formatPrice(high), _red),
              ],
            ),
            const SizedBox(height: 2),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                _buildInfoItem('低', _formatPrice(low), _green),
                const SizedBox(width: 12),
                _buildInfoItem('收', _formatPrice(close), isUp ? _green : _red),
              ],
            ),
            const SizedBox(height: 2),
            _buildInfoItem('量', _formatVolume(volume), _grayText),
          ],
        ),
      ),
    );
  }

  Widget _buildInfoItem(String label, String value, Color valueColor) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          '$label: ',
          style: const TextStyle(fontSize: 10, color: _grayText),
        ),
        Text(
          value,
          style: TextStyle(fontSize: 10, fontWeight: FontWeight.w500, color: valueColor),
        ),
      ],
    );
  }

  String _formatPrice(double price) {
    if (price >= 1) return price.toStringAsFixed(4);
    if (price >= 0.0001) return price.toStringAsFixed(6);
    return price.toStringAsExponential(2);
  }

  String _formatVolume(double volume) {
    if (volume >= 1000000) return '${(volume / 1000000).toStringAsFixed(2)}M';
    if (volume >= 1000) return '${(volume / 1000).toStringAsFixed(2)}K';
    return volume.toStringAsFixed(2);
  }

  String _formatDateTime(DateTime time) {
    return '${time.month}/${time.day} ${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}';
  }

  double _calcPriceY(_VisibleData visibleData, double price, double chartHeight) {
    if (visibleData.klines.isEmpty) return chartHeight / 2;

    double minPrice = double.infinity;
    double maxPrice = double.negativeInfinity;
    for (final kline in visibleData.klines) {
      final low = double.tryParse(kline.low) ?? 0;
      final high = double.tryParse(kline.high) ?? 0;
      if (low < minPrice) minPrice = low;
      if (high > maxPrice) maxPrice = high;
    }

    final range = maxPrice - minPrice;
    // 防止 range 为 0 导致 NaN
    final safeRange = range > 0 ? range : (maxPrice > 0 ? maxPrice * 0.1 : 1.0);
    final padding = safeRange * 0.1;
    minPrice -= padding;
    maxPrice += padding;

    final adjustedRange = maxPrice - minPrice;
    if (adjustedRange <= 0) return chartHeight / 2;

    final y = 10 + ((maxPrice - price) / adjustedRange) * (chartHeight - 20);
    return y.clamp(0.0, chartHeight - 20);
  }
}

class _VisibleData {
  final List<Kline> klines;
  final int startIndex;
  final double candleWidth;

  _VisibleData({required this.klines, required this.startIndex, required this.candleWidth});
}
