Python+MYSQL+SKLearn对国内商品期货聚类

参考了SKLearn官网上的示例Visualizing the stock market structure
结果如图:

在这里插入图片描述

安装MYSQL,创建数据库

sudo apt install mysql-server
sudo mysql

sudo打开mysql后创建名为ClusteringFutures的数据库,并创建和授权一般用户。Ctrl+c退出

CREATE DATABASE ClusteringFutures;
USE ClusteringFutures;
CREATE USER 'IVIVI_PLUS'@'localhost' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON ClusteringFutures.* TO 'IVIVI_PLUS'@'localhost';
FLUSH PRIVILEGES;

验证以上操作,以一般用户进入数据库。

mysql -u IVIVI_PLUS -p ClusteringFutures

至此,MYSQL准备工作完成。

Python端

基本流程:
1、从新浪财经获取国内商品期货的日K线数据。
2、数据导入MYSQL
3、清洗数据
4、计算单日涨跌幅,作为聚类模型训练的输入
5、SKLearn聚类
6、Matplotlib进行可视化

import requests
import pymysql
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from sklearn import cluster, covariance, manifold

# 商品期货代码与名称字典
# symbol_dict = {
#     'TA0': 'PTA',
#     'OI0': '菜油',
#     'RS0': '菜籽',
#     'RM0': '菜粕',
#     'ZC0': '动力煤',
#     'WH0': '强麦',
#     'JR0': '粳稻',
#     'SR0': '白糖',
#     'CF0': '棉花',
#     'RI0': '早籼稻',
#     'MA0': '甲醇',
#     'FG0': '玻璃',
#     'LR0': '晚籼稻',
#     'SF0': '硅铁',
#     'SM0': '锰硅',
#     'CY0': '棉纱',
#     'AP0': '苹果',
#     'CJ0': '红枣',
#     'V0': 'PVC',
#     'P0': '棕榈油',
#     'B0': '豆二',
#     'M0': '豆粕',
#     'I0': '铁矿石',
#     'JD0': '鸡蛋',
#     'L0': '塑料',
#     'PP0': '聚丙烯',
#     'FB0': '纤维板',
#     'BB0': '胶合板',
#     'Y0': '豆油',
#     'C0': '玉米',
#     'A0': '豆一',
#     'J0': '焦炭',
#     'JM0': '焦煤',
#     'CS0': '淀粉',
#     'EG0': '乙二醇',
#     'FU0': '燃料油',
#     'SC0': '上海原油',
#     'AL0': '铝',
#     'RU0': '天然橡胶',
#     'ZN0': '沪锌',
#     'CU0': '铜',
#     'AU0': '黄金',
#     'RB0': '螺纹钢',
#     'WR0': '线材',
#     'PB0': '铅',
#     'AG0': '白银',
#     'BU0': '沥青',
#     'HC0': '热轧卷板',
#     'SN0': '锡',
#     'NI0': '镍',
#     'SP0': '纸浆'}

symbol_dict = {
    'TA0': 'PTA',
    'OI0': '菜油',
    'RM0': '菜粕',
    'WH0': '强麦',
    'SR0': '白糖',
    'CF0': '棉花',
    'MA0': '甲醇',
    'FG0': '玻璃',
    'SM0': '锰硅',
    'V0': 'PVC',
    'P0': '棕榈油',
    'M0': '豆粕',
    'I0': '铁矿石',
    'JD0': '鸡蛋',
    'L0': '塑料',
    'PP0': '聚丙烯',
    'FB0': '纤维板',
    'BB0': '胶合板',
    'Y0': '豆油',
    'C0': '玉米',
    'A0': '豆一',
    'J0': '焦炭',
    'JM0': '焦煤',
    'CS0': '淀粉',
    'AL0': '铝',
    'RU0': '天然橡胶',
    'ZN0': '沪锌',
    'CU0': '铜',
    'AU0': '黄金',
    'RB0': '螺纹钢',
    'PB0': '铅',
    'AG0': '白银',
    'HC0': '热轧卷板'}

# 将期货字典的keys和values排序后,分别存入symbol_list和names备用
symbol_list, names = np.array(sorted(symbol_dict.items())).T
# 将symbol从np.array转为list
symbol_list = list(symbol_list)


# 创建期货数据表的函数
def creat_future_table(symbol):
    future_code = symbol
    # 向新浪财经api请求历史数据
    url_str = ('http://stock2.finance.sina.com.cn/futures/api/json.php/IndexService.getInnerFuturesDailyKLine?symbol=' +
               future_code)
    r = requests.get(url_str)
    daily_klines = r.json()
    daily_klines_lists = list(daily_klines)
    # 数据写入数据库,表格名为期货代码
    future_db = pymysql.connect('localhost', 'IVIVI_PLUS', '123456', 'ClusteringFutures')
    cursor = future_db.cursor()
    # 如果已存在该期货表格,则删除
    cursor.execute("DROP TABLE IF EXISTS " + future_code)
    # 创建表格,“交易日期”(主键)、开盘价、最高价、最低价、收盘价、成交量
    sql = "CREATE TABLE " + future_code + """ (
             price_date DATE NOT NULL PRIMARY KEY,
             open_price DECIMAL(19, 4),
             high_price DECIMAL(19, 4),
             low_price DECIMAL(19, 4),
             close_price DECIMAL(19, 4),
             volume BIGINT)"""
    # 运行创建表格的sql语句
    cursor.execute(sql)

    # 插入数据(ps:新浪api返回数据转字符串时会多余'['和']',所以进行切片)
    for i in daily_klines_lists:
        sql = "INSERT INTO " + future_code + """ (price_date, open_price, high_price, low_price, close_price, volume)
               VALUES (""" + str(i)[1:-1] + ")"

        try:
            # 执行sql语句
            cursor.execute(sql)
            # 提交到数据库执行
            future_db.commit()
        except:
            print('rollback table %s' %s (future_code))
            # 如果发生错误则回滚
            future_db.rollback()

    # 关闭数据库连接
    future_db.close()


# 删除表格中垃圾数据行的函数
def delete_rows(symbol):
    future_code = symbol
    future_db = pymysql.connect('localhost', 'IVIVI_PLUS', '123456', 'ClusteringFutures')
    cursor = future_db.cursor()
    # 简单认为,开盘价或收盘价或成交量是0的行为垃圾数据
    sql = "DELETE FROM " + future_code + " WHERE open_price = 0 OR close_price = 0 OR volume = 0"
    cursor.execute(sql)
    future_db.commit()
    future_db.close()


# 返回一个表格中,全部交易日期的函数
def select_columns(symbol):
    future_code = symbol
    future_db = pymysql.connect('localhost', 'IVIVI_PLUS', '123456', 'ClusteringFutures')
    cursor = future_db.cursor()
    sql = "SELECT price_date FROM " + future_code
    cursor.execute(sql)
    r = cursor.fetchall()
    future_db.close()
    return r


# 查询某期货某一天的某项数据的函数
def select_a_data(symbol, date, data_name):
    future_code = symbol
    future_db = pymysql.connect('localhost', 'IVIVI_PLUS', '123456', 'ClusteringFutures')
    cursor = future_db.cursor()
    sql = "SELECT %s FROM " % data_name + future_code + " WHERE price_date = \'" + date + "\'"
    cursor.execute(sql)
    r = cursor.fetchall()
    future_db.close()
    return r


print('对 %d 只期货进行聚类' % len(symbol_list))

# 对symbol_list中的所有期货创建数据表,并删除垃圾行
for s in symbol_list:
    print(symbol_dict[s])
    creat_future_table(s)
    delete_rows(s)

# 找出symbol_list中的所有期货的共有交易日
date_set_list = []  # 交易日组成的集合的列表(为了方便后续的求交集工作,所以转为集合)

for s in symbol_list:
    r = select_columns(s)
    date_set_list.append(set(r))

com_date_set = date_set_list[0]  # 共有交易日集合,初始等于第一支期货的交易日集合

# 对date_set_list中的全部日期集合求交集,获得共有交易日
for i in range(len(symbol_list)):
    com_date_set = com_date_set.intersection(date_set_list[i])

com_date_list = list(com_date_set)
com_date_list.sort()

# 将共有交易日以字符串形式保存,方便后续使用
str_com_date_list = []
for i in com_date_list:
    str_com_date_list.append(str(i[0]))

# 打印共有交易日天数
print('将要聚类的期货共有 %d 条有效交易数据' % len(str_com_date_list))

# 将共有交易日的收盘价和开盘价转为np.array格式
# 转置后每一列是同一个期货每个交易日的收盘价或开盘价
# 行数为交易日天数,列数为期货数量
close_prices_list = []
for s in symbol_list:
    tmp_list = []
    for date in str_com_date_list:
        tmp_list.append(select_a_data(s, date, 'close_price')[0][0])
    else:
        close_prices_list.append(tmp_list)
close_prices = np.array(close_prices_list).T

open_prices_list = []
for s in symbol_list:
    tmp_list = []
    for date in str_com_date_list:
        tmp_list.append(select_a_data(s, date, 'open_price')[0][0])
    else:
        open_prices_list.append(tmp_list)
open_prices = np.array(open_prices_list).T

# 计算每个期货的每个单日涨跌幅数组作为模型输入
X = (close_prices - open_prices) / open_prices * 100

# 查看输入形状
print('验证输入数据形状')
print(X.shape)

# 使用sk_learn预设模型进行聚类
edge_model = covariance.GraphicalLassoCV()
edge_model.fit(X)

_, labels = cluster.affinity_propagation(edge_model.covariance_)
n_labels = labels.max()

# #############################################################################
# Find a low-dimension embedding for visualization: find the best position of
# the nodes (the stocks) on a 2D plane

# We use a dense eigen_solver to achieve reproducibility (arpack is
# initiated with random vectors that we don't control). In addition, we
# use a large number of neighbors to capture the large-scale structure.
node_position_model = manifold.LocallyLinearEmbedding(
    n_components=2, eigen_solver='dense', n_neighbors=6)

embedding = node_position_model.fit_transform(X.T).T

# #############################################################################
# Visualization
plt.rcParams['font.sans-serif'] = ['TW-Sung']  # 指定中文字体,解决中文乱码
plt.figure(1, facecolor='w', figsize=(10, 8))
plt.clf()
ax = plt.axes([0., 0., 1., 1.])
plt.axis('off')

# Display a graph of the partial correlations
partial_correlations = edge_model.precision_.copy()
d = 1 / np.sqrt(np.diag(partial_correlations))
partial_correlations *= d
partial_correlations *= d[:, np.newaxis]
non_zero = (np.abs(np.triu(partial_correlations, k=1)) > 0.02)

# Plot the nodes using the coordinates of our embedding
plt.scatter(embedding[0], embedding[1], s=100 * d ** 2, c=labels,
            cmap=plt.cm.nipy_spectral)

# Plot the edges
start_idx, end_idx = np.where(non_zero)
# a sequence of (*line0*, *line1*, *line2*), where::
#            linen = (x0, y0), (x1, y1), ... (xm, ym)
segments = [[embedding[:, start], embedding[:, stop]]
            for start, stop in zip(start_idx, end_idx)]
values = np.abs(partial_correlations[non_zero])
lc = LineCollection(segments,
                    zorder=0, cmap=plt.cm.hot_r,
                    norm=plt.Normalize(0, .7 * values.max()))
lc.set_array(values)
lc.set_linewidths(15 * values)
ax.add_collection(lc)

# Add a label to each node. The challenge here is that we want to
# position the labels to avoid overlap with other labels
for index, (name, label, (x, y)) in enumerate(
        zip(names, labels, embedding.T)):

    dx = x - embedding[0]
    dx[index] = 1
    dy = y - embedding[1]
    dy[index] = 1
    this_dx = dx[np.argmin(np.abs(dy))]
    this_dy = dy[np.argmin(np.abs(dx))]
    if this_dx > 0:
        horizontalalignment = 'left'
        x = x + .002
    else:
        horizontalalignment = 'right'
        x = x - .002
    if this_dy > 0:
        verticalalignment = 'bottom'
        y = y + .002
    else:
        verticalalignment = 'top'
        y = y - .002
    plt.text(x, y, name, size=10,
             horizontalalignment=horizontalalignment,
             verticalalignment=verticalalignment,
             bbox=dict(facecolor='w',
                       edgecolor=plt.cm.nipy_spectral(label / float(n_labels)),
                       alpha=.6))

plt.xlim(embedding[0].min() - .15 * embedding[0].ptp(),
         embedding[0].max() + .10 * embedding[0].ptp(),)
plt.ylim(embedding[1].min() - .03 * embedding[1].ptp(),
         embedding[1].max() + .03 * embedding[1].ptp())

plt.show()

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值