python:将股票市价数据转换为 midi 文件

这是一个将股票数据转换为 MIDI音乐的 python程序示例。程序使用 Tushare 获取股票数据,并将收盘价映射为 MIDI音符的音高:
pip install tushare
python 3.9  tushare==1.4.21
pip install midiutil
  MIDIUtil==1.2.1

编写 stock2midi.py  如下

# -*- coding: utf-8 -*-
"""
使用 tushare 获取股票数据并转换为 MIDI文件
需要先安装依赖:
pip install tushare midiutil
"""
import sys
import tushare as ts
from midiutil import MIDIFile

# 配置Tushare token(需在https://tushare.pro注册获取)
ts.set_token('你的Tushare Token')
pro = ts.pro_api()

def stock_to_midi(symbol, start_date, end_date, output_file='stock_melo.mid'):
    # 获取股票日线数据
    df = pro.daily(ts_code=symbol, start_date=start_date, end_date=end_date)
    df = df.sort_values('trade_date')  # 按日期排序
    
    # 提取收盘价序列
    prices = df['close'].astype(float).tolist()
    
    # MIDI参数配置
    min_note = 48  # C3(MIDI音符范围最小值)
    max_note = 84  # C5(MIDI音符范围最大值)
    track = 0
    channel = 0
    tempo = 120    # BPM
    volume = 100   # 音量(0-127)
    
    # 创建MIDI文件
    midi = MIDIFile(1)
    midi.addTrackName(track, 0, f"Stock {symbol}")
    midi.addTempo(track, 0, tempo)
    
    # 数据归一化处理
    min_price = min(prices)
    max_price = max(prices)
    price_range = max_price - min_price
    
    # 生成音符序列
    time_counter = 0  # 时间指针(单位:拍)
    for price in prices:
        if price_range == 0:  # 处理价格无波动的情况
            pitch = (max_note + min_note) // 2
        else:
            normalized = (price - min_price) / price_range
            pitch = min_note + int(normalized * (max_note - min_note))
        
        # 添加音符(每个音符持续1拍,间隔1拍)
        midi.addNote(track, channel, pitch, time_counter, 1, volume)
        time_counter += 2
    
    # 保存MIDI文件
    with open(output_file, 'wb') as f:
        midi.writeFile(f)
    print(f"MIDI文件已生成:{output_file}")

if __name__ == '__main__':
    # 示例参数(沪市示例:上证指数)
    stock_to_midi(
        symbol='000001.SZ',
        start_date='20240101',
        end_date='20250330',
        output_file='stock_melo.mid'
    )

运行 python  stock2midi.py 

使用说明:

  1. 需要先到Tushare官网注册获取API Token,替换代码中的你的Tushare Token

  2. 可调整参数:

    • symbol:股票代码(默认上证指数)

    • start_date/end_date:数据时间范围

    • output_file:输出MIDI文件名

    • min_note/max_note:音符范围(MIDI音符值范围0-127)

  3. 音乐特征说明:

    • 每个交易日对应一个音符

    • 收盘价越高,音符音高越高

    • 每个音符持续1拍,间隔1拍(可通过修改时间计数器调整节奏)

    • 默认使用钢琴音色(MIDI通道0)

生成MIDI文件后,可使用任何音乐播放器播放,或用MIDI合成器转换为其他音色。

注意:由于股票数据波动性不同,生成的音乐效果也会有显著差异。
建议选择波动较大(max/min >1.3)的个股或指数数据进行尝试。

 编写 play_mid.py  如下

# -*- coding: utf-8 -*-
import os
import sys
import time
from tkinter import filedialog
import traceback
import pygame
from pygame import mixer

def mixer_init():
    freq = 44100
    bitsize = -16
    channels = 2
    buffer = 2048
    mixer.init(freq, bitsize, channels, buffer)
    # optional volume 0 to 1.0
    mixer.music.set_volume(0.9)

def play_mid(file):
    if mixer.music.get_busy():
        mixer.music.fadeout(1000)
        mixer.music.stop()
    clock = pygame.time.Clock()
    try:
        mixer.music.load(file)
    except:
        print(traceback.format_exc())
    mixer.music.play()
    while mixer.music.get_busy():
        clock.tick(30)

# main()
f1 = ''
if len(sys.argv) ==1:
    filetypes = [('mid file','.mid'),('mp3 file','.mp3'),('wav file','.wav')]
    f1 = filedialog.askopenfilename(initialdir='D:/Music', filetypes=filetypes)
elif len(sys.argv) ==2:
    f1 = sys.argv[1]
else:
    print('usage: python play_mid.py file1.mid')
    print('usage: python play_mid.py file1.mp3')
    print('usage: python play_mid.py file1.wav')
    sys.exit(1)

if not os.path.exists(f1):
    print(f"{f1} is not exists.")
    sys.exit(2)

fn,ext = os.path.splitext(f1)
if ext.lower() not in ('.mid','.mp3','.wav'):
    print('.ext is not (.mid , .mp3','.wav')
    sys.exit(2)

print(f1)
mixer_init()
time1 = time.time()
try:
    play_mid(f1)
except KeyboardInterrupt as ex:
    # if user hits Ctrl+C then exit
    # (works only in console mode)
    mixer.music.fadeout(1000)
    mixer.music.stop()
    raise SystemExit from ex
mixer.music.stop()
time2 = time.time()
print("run time: %.3f s" % (time2-time1))

运行 python play_mid.py stock_melo.mid

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值