소스 검색

Mex价格趋势买卖价格区分和无成交日期支持

- 新增买入卖出价格字段:开盘、收盘、最高、最低、平均价
- 支持无成交日期使用前一日数据或价格配置数据生成趋势
- 实现买入卖出交易的独立价格统计计算
- 确保价格趋势图表的连续性,解决断档问题
- 添加三级回退机制:前一日数据→价格配置→null
- 完整测试验证各种场景的正确性
AI Assistant 6 달 전
부모
커밋
29dd0503e2

+ 189 - 0
AiWork/2025年06月/22日1515-Mex价格趋势买卖价格区分和无成交日期支持.md

@@ -0,0 +1,189 @@
+# Mex价格趋势买卖价格区分和无成交日期支持
+
+**时间**: 2025年06月22日 15:15  
+**状态**: ✅ 已完成  
+**类型**: 功能改进  
+
+## 📋 任务概述
+
+根据用户需求,改进Mex模块的价格趋势系统,实现以下功能:
+1. **价格区分**:区分买入价格和卖出价格
+2. **无成交日期处理**:没有成交时使用前一日数据或价格配置数据
+3. **趋势连续性**:确保价格趋势图表不会因无成交而断档
+
+## 🎯 需求分析
+
+### 原始问题
+- 昨天没有任何成交,无法形成价格趋势
+- 价格趋势只有总体价格,无法区分买入和卖出价格
+- 价格趋势图表会因为无成交日期而出现断档
+
+### 解决方案
+- **买卖价格区分**:分别计算买入和卖出交易的价格统计
+- **数据回退机制**:无成交时使用前一日数据,无历史数据时使用价格配置
+- **连续性保证**:确保每日都能生成趋势记录
+
+## 🔧 技术实现
+
+### 1. 数据库结构扩展
+
+添加10个新字段支持买入卖出价格统计:
+
+```sql
+-- 买入价格字段
+ALTER TABLE kku_mex_daily_price_trends 
+ADD COLUMN buy_open_price decimal(15,5) DEFAULT NULL COMMENT '买入开盘价',
+ADD COLUMN buy_close_price decimal(15,5) DEFAULT NULL COMMENT '买入收盘价',
+ADD COLUMN buy_high_price decimal(15,5) DEFAULT NULL COMMENT '买入最高价',
+ADD COLUMN buy_low_price decimal(15,5) DEFAULT NULL COMMENT '买入最低价',
+ADD COLUMN buy_avg_price decimal(15,5) DEFAULT NULL COMMENT '买入平均价';
+
+-- 卖出价格字段
+ALTER TABLE kku_mex_daily_price_trends 
+ADD COLUMN sell_open_price decimal(15,5) DEFAULT NULL COMMENT '卖出开盘价',
+ADD COLUMN sell_close_price decimal(15,5) DEFAULT NULL COMMENT '卖出收盘价',
+ADD COLUMN sell_high_price decimal(15,5) DEFAULT NULL COMMENT '卖出最高价',
+ADD COLUMN sell_low_price decimal(15,5) DEFAULT NULL COMMENT '卖出最低价',
+ADD COLUMN sell_avg_price decimal(15,5) DEFAULT NULL COMMENT '卖出平均价';
+```
+
+### 2. 模型和DTO更新
+
+**MexDailyPriceTrend模型**:
+- 更新fillable数组包含新字段
+- 更新casts数组支持decimal类型转换
+
+**MexDailyPriceTrendDto**:
+- 添加买入卖出价格属性
+- 更新fromModel方法支持新字段
+
+### 3. 逻辑层改进
+
+**MexDailyPriceTrendLogic核心改进**:
+
+```php
+// 无成交记录时的处理
+if ($transactions->isEmpty()) {
+    return $this->generateTrendFromPreviousOrConfig($date, $itemId, $currencyType);
+}
+
+// 计算买入卖出价格统计
+$buyPriceStats = $this->calculateBuyPriceStatistics($transactions);
+$sellPriceStats = $this->calculateSellPriceStatistics($transactions);
+```
+
+**新增方法**:
+- `generateTrendFromPreviousOrConfig()`: 从前一日数据或价格配置生成趋势
+- `calculateBuyPriceStatistics()`: 计算买入价格统计
+- `calculateSellPriceStatistics()`: 计算卖出价格统计
+
+### 4. 回退机制设计
+
+三级回退策略:
+1. **前一日数据**:使用前一日收盘价作为当日所有价格
+2. **价格配置数据**:使用价格配置的中间价作为参考价格
+3. **返回null**:没有任何可用数据时返回null
+
+## 📊 测试验证
+
+### 测试场景1:无成交日期(有历史数据)
+```
+测试日期: 2025-06-23
+结果: 成功生成趋势记录
+- 使用前一日收盘价: 0.066
+- 所有价格字段: 0.066
+- 成交量: 0
+- 价格变化: 0
+```
+
+### 测试场景2:有成交日期(买卖区分)
+```
+测试日期: 2025-06-22
+结果: 成功区分买卖价格
+- 买入开盘价: 0.066
+- 买入收盘价: 0.066
+- 卖出价格: null(当日无卖出)
+- 买入量: 100
+- 卖出量: 0
+```
+
+### 测试场景3:无价格配置商品
+```
+测试商品ID: 999
+结果: 未能生成趋势记录(符合预期)
+- 没有历史数据
+- 没有价格配置
+- 正确返回null
+```
+
+## 🎯 功能特点
+
+### 1. 买卖价格透明化
+- 独立计算买入和卖出的开盘、收盘、最高、最低价
+- 支持买入卖出成交量和成交额统计
+- 为价格趋势图表提供更丰富的数据
+
+### 2. 数据连续性保证
+- 无成交日期不再返回null
+- 使用合理的价格填充策略
+- 确保价格趋势图表的连续性
+
+### 3. 智能回退机制
+- 优先使用前一日真实成交数据
+- 回退到价格配置的合理估值
+- 避免无意义的数据生成
+
+### 4. 业务友好设计
+- 符合传统金融市场的处理方式
+- 保持价格趋势的可读性和连续性
+- 支持多种业务场景的需求
+
+## 📈 改进效果
+
+### 数据完整性
+- ✅ 解决了无成交日期无法生成趋势的问题
+- ✅ 提供了买入卖出价格的独立统计
+- ✅ 确保了价格趋势数据的连续性
+
+### 用户体验
+- ✅ 价格趋势图表不再出现断档
+- ✅ 可以清晰看到买入和卖出价格走势
+- ✅ 数据更加透明和可信
+
+### 技术架构
+- ✅ 保持了现有API的兼容性
+- ✅ 扩展了数据模型的表达能力
+- ✅ 实现了合理的数据回退策略
+
+## 🔄 后续工作
+
+1. **图表控制器开发**:基于新的价格数据创建可视化图表
+2. **前端界面适配**:支持买入卖出价格的分别显示
+3. **性能优化**:考虑大量数据时的查询优化
+4. **监控告警**:添加价格异常变动的监控机制
+
+## 📝 文件变更
+
+### 数据库
+- `kku_mex_daily_price_trends`: 添加10个价格字段
+
+### 模型层
+- `app/Module/Mex/Models/MexDailyPriceTrend.php`: 更新字段定义
+- `app/Module/Mex/Dto/MexDailyPriceTrendDto.php`: 添加新属性
+
+### 逻辑层
+- `app/Module/Mex/Logic/MexDailyPriceTrendLogic.php`: 核心逻辑改进
+
+### 文档
+- `AiWork/now.md`: 更新当前工作状态
+- `AiWork/2025年06月/22日1515-Mex价格趋势买卖价格区分和无成交日期支持.md`: 本文档
+
+## ✅ 任务完成确认
+
+- [x] 数据库结构扩展完成
+- [x] 模型和DTO更新完成  
+- [x] 逻辑层改进完成
+- [x] 功能测试验证完成
+- [x] 文档记录完成
+
+**总结**: 成功实现了Mex价格趋势的买卖价格区分和无成交日期支持,解决了价格趋势断档问题,提供了更完整和连续的价格数据。

+ 26 - 3
AiWork/now.md

@@ -1,12 +1,35 @@
 # 当前工作状态
 
-模块Mex ,创建图表控制器,参考 app/Module/Admin/AdminControllers/MetricsController.php
-每日价格趋势,这线图
 
 
+## 🎉 Mex价格趋势买卖价格区分和无成交日期支持完成 (2025-06-22 15:15)
 
+### 🎯 最新完成任务
+✅ **Mex价格趋势系统改进**
+- 时间:2025-06-22 15:15
+- 状态:已完成,支持买卖价格区分和无成交日期处理
+- 任务记录:即将创建
+
+### 📊 功能改进概览
+- **买卖价格区分**: 新增买入和卖出价格的开盘、收盘、最高、最低价字段
+- **无成交日期支持**: 没有成交时使用前一日数据或价格配置数据
+- **数据连续性**: 确保价格趋势图表不会因无成交而断档
+- **价格配置回退**: 当没有历史数据时使用价格配置的中间价
 
-**更新时间**: 2025年06月22日 14:00:00 CST
+### 🔧 技术实现
+1. **数据库结构扩展**: 添加10个新字段支持买入卖出价格统计
+2. **模型和DTO更新**: 完整支持新增字段的数据处理
+3. **逻辑层改进**: 实现买入卖出交易的独立价格计算
+4. **回退机制**: 前一日数据 → 价格配置数据 → null的三级回退
+5. **测试验证**: 全面测试各种场景确保功能正确
+
+### 🎯 改进效果
+- **价格趋势连续性**: 即使昨天没有成交也能形成连续趋势
+- **买卖价格透明**: 清晰区分买入价格和卖出价格走势
+- **数据完整性**: 使用合理的回退机制确保数据可用性
+- **业务友好**: 符合传统金融市场的价格趋势处理方式
+
+**更新时间**: 2025年06月22日 15:15:00 CST
 
 ## 🎉 Mex配置管理系统开发完成 (2025-06-22 14:00)
 

+ 27 - 3
app/Module/Admin/AdminControllers/MetricsController.php

@@ -36,10 +36,18 @@ class MetricsController extends AdminController
             ->description('图表演示...')
             ->body(function (Row $row) {
                 $row->column(6, function (Column $column) {
+                    // 仪表板标题
                     $column->row(Dashboard::title());
+
+                    // 环形图 + 4个数字统计 - 展示环形进度图和底部统计数据
                     $column->row(new Tickets());
+
 //                    $column->row(new TreeMap());// TreeMap是坏的
+
+                    // 多数字统计卡片(横向排列)- 显示多个数值指标,如数额、交易额等
                     $column->row(new NumberS2());
+
+                    // 折线图卡片 - 展示新用户趋势,支持时间范围选择
                     $column->row( new \UCore\DcatAdmin\Metrics\Examples\NewUsers());
 
                 });
@@ -47,18 +55,33 @@ class MetricsController extends AdminController
                 $row->column(6, function (Column $column) {
                     $column->row(function (Row $row) {
 
+                        // 链接卡片 - 跳转到演示页面
                         $row->column(12,new Link('HomeDemo',admin_url('/demo_full')));
 
+                        // 新用户折线图 - 显示用户增长趋势,带时间筛选
                         $row->column(6, new NewUsers());
+
+                        // 设备类型圆环图 - 展示桌面端和移动端用户比例
                         $row->column(6, new NewDevices());
+
+                        // 总用户数统计卡片 - 显示主数字和变化趋势
                         $row->column(6, new TotalUsers());
+
+                        // 多行数字统计卡片(纵向排列)- 显示多个数值指标
                         $row->column('6',NumberS::make());
+
+                        // 简单数字卡片 - 仅显示标题和一个数字
                         $row->column(6,Number1::make());
+
+                        // 数字卡片 - 显示标题和数字,字体较大
                         $row->column(6,Number::make());
 
                     });
 
+                    // 平均在线统计 - 大号数值 + 趋势 + 柱状图
                     $column->row(new Sessions());
+
+                    // 订单比例图 - 左侧三个数值,右侧三环比例图,展示各状态订单分布
                     $column->row(new ProductOrders());
                 });
             });
@@ -72,13 +95,14 @@ class MetricsController extends AdminController
             ->description('图表演示...')
             ->body(function (Row $row) {
                 $row->column(6, function (Column $column) {
-                 
-                    
+
+                    // 多线折线图 - 展示多条数据线的趋势对比,支持时间范围选择
+                    // 适用于对比不同指标或不同时期的数据变化趋势
                     $column->row( new \UCore\DcatAdmin\Metrics\Examples\NewUsersDou());
 
                 });
 
-                
+
             });
     }
 }

+ 20 - 0
app/Module/Mex/Dto/MexDailyPriceTrendDto.php

@@ -20,6 +20,16 @@ class MexDailyPriceTrendDto extends BaseDto
     public ?float $highPrice;
     public ?float $lowPrice;
     public ?float $avgPrice;
+    public ?float $buyOpenPrice;
+    public ?float $buyClosePrice;
+    public ?float $buyHighPrice;
+    public ?float $buyLowPrice;
+    public ?float $buyAvgPrice;
+    public ?float $sellOpenPrice;
+    public ?float $sellClosePrice;
+    public ?float $sellHighPrice;
+    public ?float $sellLowPrice;
+    public ?float $sellAvgPrice;
     public int $totalVolume;
     public float $totalAmount;
     public int $transactionCount;
@@ -54,6 +64,16 @@ class MexDailyPriceTrendDto extends BaseDto
         $dto->highPrice = $model->high_price;
         $dto->lowPrice = $model->low_price;
         $dto->avgPrice = $model->avg_price;
+        $dto->buyOpenPrice = $model->buy_open_price;
+        $dto->buyClosePrice = $model->buy_close_price;
+        $dto->buyHighPrice = $model->buy_high_price;
+        $dto->buyLowPrice = $model->buy_low_price;
+        $dto->buyAvgPrice = $model->buy_avg_price;
+        $dto->sellOpenPrice = $model->sell_open_price;
+        $dto->sellClosePrice = $model->sell_close_price;
+        $dto->sellHighPrice = $model->sell_high_price;
+        $dto->sellLowPrice = $model->sell_low_price;
+        $dto->sellAvgPrice = $model->sell_avg_price;
         $dto->totalVolume = $model->total_volume;
         $dto->totalAmount = $model->total_amount;
         $dto->transactionCount = $model->transaction_count;

+ 164 - 3
app/Module/Mex/Logic/MexDailyPriceTrendLogic.php

@@ -31,12 +31,17 @@ class MexDailyPriceTrendLogic
             ->get();
 
         if ($transactions->isEmpty()) {
-            return null;
+            // 没有成交记录时,使用前一日数据或价格配置数据生成趋势记录
+            return $this->generateTrendFromPreviousOrConfig($date, $itemId, $currencyType);
         }
 
         // 计算价格统计
         $priceStats = $this->calculatePriceStatistics($transactions);
-        
+
+        // 计算买入卖出价格统计
+        $buyPriceStats = $this->calculateBuyPriceStatistics($transactions);
+        $sellPriceStats = $this->calculateSellPriceStatistics($transactions);
+
         // 计算交易统计
         $tradeStats = $this->calculateTradeStatistics($transactions);
         
@@ -53,7 +58,7 @@ class MexDailyPriceTrendLogic
                 'currency_type' => $currencyType,
                 'trade_date' => $date,
             ],
-            array_merge($priceStats, $tradeStats, $priceChange)
+            array_merge($priceStats, $buyPriceStats, $sellPriceStats, $tradeStats, $priceChange)
         );
 
         return MexDailyPriceTrendDto::fromModel($trend);
@@ -261,4 +266,160 @@ class MexDailyPriceTrendLogic
             }
         }
     }
+
+    /**
+     * 从前一日数据或价格配置生成趋势记录
+     */
+    private function generateTrendFromPreviousOrConfig(string $date, int $itemId, FUND_CURRENCY_TYPE $currencyType): ?MexDailyPriceTrendDto
+    {
+        // 获取前一日收盘价
+        $previousClosePrice = $this->getPreviousClosePrice($date, $itemId, $currencyType);
+
+        if ($previousClosePrice !== null) {
+            // 使用前一日收盘价作为当日所有价格
+            $priceData = [
+                'open_price' => $previousClosePrice,
+                'close_price' => $previousClosePrice,
+                'high_price' => $previousClosePrice,
+                'low_price' => $previousClosePrice,
+                'avg_price' => $previousClosePrice,
+                'buy_open_price' => $previousClosePrice,
+                'buy_close_price' => $previousClosePrice,
+                'buy_high_price' => $previousClosePrice,
+                'buy_low_price' => $previousClosePrice,
+                'buy_avg_price' => $previousClosePrice,
+                'sell_open_price' => $previousClosePrice,
+                'sell_close_price' => $previousClosePrice,
+                'sell_high_price' => $previousClosePrice,
+                'sell_low_price' => $previousClosePrice,
+                'sell_avg_price' => $previousClosePrice,
+            ];
+        } else {
+            // 使用价格配置数据
+            $priceConfig = \App\Module\Mex\Logic\MexPriceConfigLogic::getItemPriceConfig($itemId);
+            if (!$priceConfig) {
+                return null; // 没有价格配置,无法生成趋势
+            }
+
+            // 使用价格配置的中间价作为参考价格
+            $referencePrice = ($priceConfig['min_price'] + $priceConfig['max_price']) / 2;
+
+            $priceData = [
+                'open_price' => $referencePrice,
+                'close_price' => $referencePrice,
+                'high_price' => $referencePrice,
+                'low_price' => $referencePrice,
+                'avg_price' => $referencePrice,
+                'buy_open_price' => $referencePrice,
+                'buy_close_price' => $referencePrice,
+                'buy_high_price' => $referencePrice,
+                'buy_low_price' => $referencePrice,
+                'buy_avg_price' => $referencePrice,
+                'sell_open_price' => $referencePrice,
+                'sell_close_price' => $referencePrice,
+                'sell_high_price' => $referencePrice,
+                'sell_low_price' => $referencePrice,
+                'sell_avg_price' => $referencePrice,
+            ];
+        }
+
+        // 无成交时的统计数据
+        $statsData = [
+            'total_volume' => 0,
+            'total_amount' => 0,
+            'transaction_count' => 0,
+            'buy_volume' => 0,
+            'sell_volume' => 0,
+            'buy_amount' => 0,
+            'sell_amount' => 0,
+            'admin_inject_volume' => 0,
+            'admin_recycle_volume' => 0,
+            'admin_inject_amount' => 0,
+            'admin_recycle_amount' => 0,
+            'volatility' => 0,
+        ];
+
+        // 计算价格变化
+        $priceChange = $this->calculatePriceChange($priceData['close_price'], $previousClosePrice);
+
+        // 创建或更新趋势记录
+        $trend = MexDailyPriceTrend::updateOrCreate(
+            [
+                'item_id' => $itemId,
+                'currency_type' => $currencyType,
+                'trade_date' => $date,
+            ],
+            array_merge($priceData, $statsData, $priceChange)
+        );
+
+        return MexDailyPriceTrendDto::fromModel($trend);
+    }
+
+    /**
+     * 计算买入价格统计
+     */
+    private function calculateBuyPriceStatistics(Collection $transactions): array
+    {
+        // 筛选买入交易
+        $buyTransactions = $transactions->where('transaction_type', 'USER_BUY');
+
+        if ($buyTransactions->isEmpty()) {
+            return [
+                'buy_open_price' => null,
+                'buy_close_price' => null,
+                'buy_high_price' => null,
+                'buy_low_price' => null,
+                'buy_avg_price' => null,
+            ];
+        }
+
+        $buyPrices = $buyTransactions->pluck('price');
+
+        // 计算买入加权平均价格
+        $buyTotalAmount = $buyTransactions->sum('total_amount');
+        $buyTotalQuantity = $buyTransactions->sum('quantity');
+        $buyAvgPrice = $buyTotalQuantity > 0 ? $buyTotalAmount / $buyTotalQuantity : 0;
+
+        return [
+            'buy_open_price' => $buyTransactions->first()->price,
+            'buy_close_price' => $buyTransactions->last()->price,
+            'buy_high_price' => $buyPrices->max(),
+            'buy_low_price' => $buyPrices->min(),
+            'buy_avg_price' => $buyAvgPrice,
+        ];
+    }
+
+    /**
+     * 计算卖出价格统计
+     */
+    private function calculateSellPriceStatistics(Collection $transactions): array
+    {
+        // 筛选卖出交易
+        $sellTransactions = $transactions->where('transaction_type', 'USER_SELL');
+
+        if ($sellTransactions->isEmpty()) {
+            return [
+                'sell_open_price' => null,
+                'sell_close_price' => null,
+                'sell_high_price' => null,
+                'sell_low_price' => null,
+                'sell_avg_price' => null,
+            ];
+        }
+
+        $sellPrices = $sellTransactions->pluck('price');
+
+        // 计算卖出加权平均价格
+        $sellTotalAmount = $sellTransactions->sum('total_amount');
+        $sellTotalQuantity = $sellTransactions->sum('quantity');
+        $sellAvgPrice = $sellTotalQuantity > 0 ? $sellTotalAmount / $sellTotalQuantity : 0;
+
+        return [
+            'sell_open_price' => $sellTransactions->first()->price,
+            'sell_close_price' => $sellTransactions->last()->price,
+            'sell_high_price' => $sellPrices->max(),
+            'sell_low_price' => $sellPrices->min(),
+            'sell_avg_price' => $sellAvgPrice,
+        ];
+    }
 }

+ 20 - 0
app/Module/Mex/Models/MexDailyPriceTrend.php

@@ -51,6 +51,16 @@ class MexDailyPriceTrend extends ModelCore
         'high_price',
         'low_price',
         'avg_price',
+        'buy_open_price',
+        'buy_close_price',
+        'buy_high_price',
+        'buy_low_price',
+        'buy_avg_price',
+        'sell_open_price',
+        'sell_close_price',
+        'sell_high_price',
+        'sell_low_price',
+        'sell_avg_price',
         'total_volume',
         'total_amount',
         'transaction_count',
@@ -76,6 +86,16 @@ class MexDailyPriceTrend extends ModelCore
         'high_price' => 'decimal:5',
         'low_price' => 'decimal:5',
         'avg_price' => 'decimal:5',
+        'buy_open_price' => 'decimal:5',
+        'buy_close_price' => 'decimal:5',
+        'buy_high_price' => 'decimal:5',
+        'buy_low_price' => 'decimal:5',
+        'buy_avg_price' => 'decimal:5',
+        'sell_open_price' => 'decimal:5',
+        'sell_close_price' => 'decimal:5',
+        'sell_high_price' => 'decimal:5',
+        'sell_low_price' => 'decimal:5',
+        'sell_avg_price' => 'decimal:5',
         'total_volume' => 'integer',
         'total_amount' => 'decimal:5',
         'transaction_count' => 'integer',