3D 图表
Chart3DScript 脚本演示如何创建 3D 图表,以可视化不同交易品种按小时统计的成交量分布。这种可视化方式可以清楚地呈现交易动态,并识别市场活跃度的高峰。

脚本运行说明
脚本分析指定时间段内的K线数据,按小时分组,并计算每小时的总成交量。结果以 3D 图表显示,各坐标轴分别表示:
- X 轴:交易品种。
- Y 轴:交易时段中的小时(0 至 23)。
- Z 轴:成交量。
3D 图表的用途
市场活动分析
3D 图表可以评估多个交易品种在什么时段同时最为活跃。这有助于确定最佳交易时段,或研究全球事件对市场的影响。
交易品种比较
通过在三维空间中按小时显示成交量,交易者可以比较各交易品种的活跃程度和主要交易时段。这有助于选择特定时段内流动性最高的交易品种,或寻找活跃模式相似的交易品种,以实现投资组合多元化。
策略优化
分析成交量分布可以为优化交易策略提供依据,使策略适应市场最活跃的时段。这对算法交易和高频交易尤其重要。
脚本实现
脚本执行以下操作:
- 检查是否存在用于分析的交易品种。
- 生成 X 轴(交易品种)和 Y 轴(小时)的标签。
- 加载K线数据并进行分组。
- 按小时计算总成交量,并填充 Z 轴数据。
- 使用
panel.Draw3D方法绘制 3D 图表。
C# 脚本代码
namespace StockSharp.Algo.Analytics
{
/// <summary>
/// 该分析脚本按小时计算最大成交量分布
/// 并在 3D 图表中显示。
/// </summary>
public class Chart3DScript : IAnalyticsScript
{
Task IAnalyticsScript.Run(ILogReceiver logs, IAnalyticsPanel panel, SecurityId[] securities, DateTime from, DateTime to, IStorageRegistry storage, IMarketDataDrive drive, StorageFormats format, DataType dataType, CancellationToken cancellationToken)
{
if (securities.Length == 0)
{
logs.LogWarning("No instruments.");
return Task.CompletedTask;
}
var x = new List<string>();
var y = new List<string>();
// 填充 Y 标签
for (var h = 0; h < 24; h++)
y.Add(h.ToString());
var z = new double[securities.Length, y.Count];
for (var i = 0; i < securities.Length; i++)
{
// 如果用户取消脚本执行,则停止计算
if (cancellationToken.IsCancellationRequested)
break;
var security = securities[i];
// 填充 X 标签
x.Add(security.ToStringId());
// 获取 K线存储
var candleStorage = storage.GetCandleMessageStorage(security, dataType, drive, format);
// 获取指定期间内的可用日期
var dates = candleStorage.GetDates(from, to).ToArray();
if (dates.Length == 0)
{
logs.LogWarning("no data");
return Task.CompletedTask;
}
// 按开盘时间对 K线分组(仅时间部分,截断到 1 小时)
var byHours = candleStorage.Load(from, to)
.GroupBy(c => c.OpenTime.TimeOfDay.Truncate(TimeSpan.FromHours(1)))
.ToDictionary(g => g.Key.Hours, g => g.Sum(c => c.TotalVolume));
// 填充 Z 值
foreach (var pair in byHours)
z[i, pair.Key] = (double)pair.Value;
}
panel.Draw3D(x, y, z, "Instruments", "Hours", "Volume");
return Task.CompletedTask;
}
}
}
Python 脚本代码
import clr
# 添加 .NET 引用
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo.Analytics")
clr.AddReference("Ecng.Drawing")
from Ecng.Drawing import DrawStyles
from System.Threading.Tasks import Task
from StockSharp.Algo.Analytics import IAnalyticsScript
from storage_extensions import *
from candle_extensions import *
from chart_extensions import *
from numpy_extensions import nx
# 该分析脚本按小时计算最大成交量分布,并在 3D 图表中显示。
class chart3d_script(IAnalyticsScript):
def Run(
self,
logs,
panel,
securities,
from_date,
to_date,
storage,
drive,
format,
data_type,
cancellation_token
):
# 检查是否 没有交易品种
if not securities:
logs.LogWarning("No instruments.")
return Task.CompletedTask
x = [] # X labels for instruments
y = [] # Y labels for hours
# 用 0 到 23 小时填充 Y 标签
for h in range(24):
y.append(str(h))
# 为 Z 值创建二维数组,维度为:(交易品种数量)x(小时数)
z = [[0.0 for _ in range(len(y))] for _ in range(len(securities))]
if data_type is None:
logs.LogWarning(f"不支持的数据类型 {data_type}。")
return Task.CompletedTask
message_type = data_type.MessageType
for i, security in enumerate(securities):
# 如果用户取消脚本执行,则停止计算
if cancellation_token.IsCancellationRequested:
break
# 用工具标识符填充 X 标签
x.append(to_string_id(security))
# 获取当前工具的K线存储
candle_storage = get_candle_storage(storage, security, data_type, drive, format)
# 获取指定期间内的可用日期
dates = get_dates(candle_storage, from_date, to_date)
if len(dates) == 0:
logs.LogWarning("no data")
return Task.CompletedTask
# 按开盘时间对 K线分组(截断到最近的小时)并汇总成交量
candles = load_range(candle_storage, message_type, from_date, to_date)
by_hours = {}
for candle in candles:
hour = int(candle.OpenTime.TimeOfDay.TotalHours)
by_hours[hour] = by_hours.get(hour, 0) + candle.TotalVolume
# 填充当前工具的 Z 值
for hour, volume in by_hours.items():
if hour < len(y):
z[i][hour] = float(volume)
# 使用面板绘制 3D 图表
panel.Draw3D(x, y, nx.to2darray(z), "Instruments", "Hours", "Volume")
return Task.CompletedTask