You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PySpark将tick逐笔交易数据转换为1分钟OHLCV DataFrame

PySpark实现tick数据转1分钟OHLCV方案

需求说明

需要将逐笔tick交易数据聚合为1分钟粒度的OHLCV(Open、High、Low、Close、Volume)格式PySpark DataFrame。

现有信息

原始输入数据样例

+---------+-------+--------+----------+-------------+
|       id|  price|  volume|   capital|    timestamp|
+---------+-------+--------+----------+-------------+
|237367441|9351.71|0.043982| 411.30692|1580515200518|
|237367442|9351.71|0.001413| 13.213966|1580515200580|
|237367443|9352.86|0.001236| 11.560135|1580515200690|
|237367444|9352.85|0.001976| 18.481232|1580515201148|
|237367445| 9352.0|1.214703| 11359.902|1580515201176|
|...|...|...|...|...|
+---------+-------+--------+----------+-------------+
仅展示前20行

目标输出样例

+-------------------+---------+---------+---------+---------+------------+
|           datetime|     open|     high|      low|    close|      volume|
+-------------------+---------+---------+---------+---------+------------+
|2020-02-01 00:00:00| 9351.710| 9375.000| 9351.710| 9358.590|  532596.780|
|2020-02-01 00:01:00| 9359.880| 9366.730| 9356.750| 9359.960|  127918.275|
|2020-02-01 00:02:00| 9359.400| 9361.170| 9356.750| 9356.800|   93449.282|
|...|...|...|...|...|...|
+-------------------+---------+---------+---------+---------+------------+

已有代码

时间转换工具类

import datetime
class Datetime_manager():
    def timestamp_to_datetime_utc(x):
        return datetime.datetime.utcfromtimestamp(x/ 1000.0).strftime("%Y-%m-%d %H:%M:%S")

主逻辑代码

from Helpers.Datetime_manager import Datetime_manager
import pyspark.sql.functions as func
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType, LongType

# 初始化SparkSession
spark = SparkSession.builder.appName('tick_to_ohlcv').getOrCreate()

# 定义schema
schema = StructType([
    StructField("id", IntegerType()), 
    StructField("price", FloatType()),
    StructField("volume", FloatType()),
    StructField("capital", FloatType()),
    StructField("timestamp", LongType()),
])

# 读取数据
df = spark.read.csv('file.csv', sep=",", schema=schema)

# 转换时间格式
get_datetime = func.udf(lambda x : Datetime_manager.timestamp_to_datetime_utc(x))
df_ = df.withColumn("datetime", get_datetime(df.timestamp))
deleted_column = df_.drop('timestamp')
deleted_column.show()

聚合实现代码

方案1:兼容现有代码(使用自定义UDF)

在已有代码基础上添加以下逻辑:

from pyspark.sql import Window

# 1. 生成分钟粒度的时间分组字段
df_with_minute = deleted_column.withColumn(
    "minute_time",
    func.date_trunc("minute", func.col("datetime").cast("timestamp"))
)

# 2. 定义窗口:按分钟分组,按原始交易id排序(id自增可保证交易顺序)
window_spec = Window.partitionBy("minute_time").orderBy("id")

# 3. 计算每个分组内的指标
df_with_rn = df_with_minute \
    .withColumn("rn", func.row_number().over(window_spec)) \
    .withColumn("max_rn", func.max("rn").over(Window.partitionBy("minute_time"))) \
    .withColumn("open", func.first("price").over(window_spec)) \
    .withColumn("high", func.max("price").over(Window.partitionBy("minute_time"))) \
    .withColumn("low", func.min("price").over(Window.partitionBy("minute_time"))) \
    .withColumn("close", func.last("price").over(window_spec)) \
    .withColumn("volume", func.sum("volume").over(Window.partitionBy("minute_time")))

# 4. 去重,每个分钟只保留一行结果
ohlcv_df = df_with_rn \
    .filter(func.col("rn") == func.col("max_rn")) \
    .select(
        func.col("minute_time").alias("datetime"),
        func.round("open", 3).alias("open"),
        func.round("high", 3).alias("high"),
        func.round("low", 3).alias("low"),
        func.round("close", 3).alias("close"),
        func.round("volume", 3).alias("volume")
    ) \
    .orderBy("datetime")

# 输出结果
ohlcv_df.show()

方案2:性能优化版(替换自定义UDF为PySpark内置函数)

自定义UDF在大数据量下性能较差,可直接使用PySpark内置时间函数处理时间戳,无需引入外部工具类:

import pyspark.sql.functions as func
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType, LongType

# 初始化SparkSession
spark = SparkSession.builder.appName('tick_to_ohlcv').getOrCreate()

# 定义schema
schema = StructType([
    StructField("id", IntegerType()), 
    StructField("price", FloatType()),
    StructField("volume", FloatType()),
    StructField("capital", FloatType()),
    StructField("timestamp", LongType()),
])

# 读取数据
df = spark.read.csv('file.csv', sep=",", schema=schema)

# 直接用内置函数转换时间戳并截断到分钟
df_with_minute = df.withColumn(
    "minute_time",
    func.date_trunc("minute", func.to_timestamp(func.col("timestamp")/1000))
)

# 聚合逻辑和方案1一致
window_spec = Window.partitionBy("minute_time").orderBy("id")

ohlcv_df = df_with_minute \
    .withColumn("rn", func.row_number().over(window_spec)) \
    .withColumn("max_rn", func.max("rn").over(Window.partitionBy("minute_time"))) \
    .withColumn("open", func.first("price").over(window_spec)) \
    .withColumn("high", func.max("price").over(Window.partitionBy("minute_time"))) \
    .withColumn("low", func.min("price").over(Window.partitionBy("minute_time"))) \
    .withColumn("close", func.last("price").over(window_spec)) \
    .withColumn("volume", func.sum("volume").over(Window.partitionBy("minute_time"))) \
    .filter(func.col("rn") == func.col("max_rn")) \
    .select(
        func.col("minute_time").alias("datetime"),
        func.round("open", 3).alias("open"),
        func.round("high", 3).alias("high"),
        func.round("low", 3).alias("low"),
        func.round("close", 3).alias("close"),
        func.round("volume", 3).alias("volume")
    ) \
    .orderBy("datetime")

ohlcv_df.show()

内容的提问来源于stack exchange,提问作者Farid Xacur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 22:36:03