python训练——简单股票数据分析

本程序仅为个人学习测试使用,不做商业用途,据此操作,后果自负
主要的策略就是通过计算涨幅和平均值来判断买入与卖出的时机。
因为我自己本身对股票了解不多,所以我写的东西要为其他策略可能还是会有点困难的。

框架解释

  1. 获取数据
    用爬虫等相关操作获取到数据,并保存到本地,以避免重复爬取浪费时间与性能
  2. 将本地的数据导入我们的程序
  3. 通过保存的数据计算涨幅,并获取涨幅最大的股票
  4. 计算某段时间内的平均价格
  5. 实行买卖的判断
  6. 买操作
  7. 卖操作
  8. 画图,实现数据可视化

代码实现

做最开始的初始化

1. 输入参数的初始化
  1. codes
    传入所需要分析的代码
    列表格式,建议在定义对象之前就写好这个列表
    默认是空,也就是 “[]”
  2. in_date
    数据分析最开始的日期
    默认是2014-01-01
    这个日期在后续的计算中会一直后推,直到等于time
  3. time
    数据分析的截止日期
    默认是系统现在的日期,而且要格式化为“年-月-日”
  4. time_span_inc
    用于分析涨幅
    默认13,即求13天内的涨幅
  5. time_span_avg
    用于分析平均价格
    默认13,即求13天内的平均价格
  6. funds
    是你手上现有的资金
    默认为10w
  7. path
    传入保存地址
2. 全局变量的初始化
  1. self.df = None
    保存从本地文件中获取的数据
  2. self.the_code = {“code”: None, “price”: None}
    保存你手上持有的股票和买入的价格
    在后续中可以改为列表,然后再添加一个字典属性:持有量
  3. self.change = {“funds”: [], “date”: []}
    获取所持有资金的变化数据,为后面 数据可视化做准备
3.示例
    def __init__(self, codes=[], in_date="2014-01-01", time=time.strftime('%Y-%m-%d', time.localtime(time.time())),
                 time_span_inc=13, time_span_avg=13, funds=100000, path="D:/"):
        self.codes = codes  # 所需要获取的股票
        self.in_date = in_date  # 数据处理开始日期
        self.time = time  # 数据处理结束日期
        self.time_span_inc = time_span_inc  # 涨幅跨度
        self.time_span_avg = time_span_avg  # 平均值跨度
        self.funds = funds  # 现有资金
        self.path = path  # 获取股票数据保存的地址

        self.df = None
        self.the_code = {"code": None, "price": None}
        self.change = {"funds": [], "date": []}

在互联网上获取数据

因为爬取的方法很多很多,我只用了最简单的方法
主要是通过循环获取传入的股票代码的相关信息,并格式化保存到本地
这个方法是只需要运行一次,把数据保存下来以后可以重复使用,方便改数据调整方案。

示例
  1. 获取的初步结果,所有相关数据都有,但是我们只要收盘的数据
    在这里插入图片描述
  2. 筛选并保存数据
    首先将“Close”这一列的标签索引重命名,然后只把这一列保存下来
    这个就是保存的格式
    在个别电脑上会出现只保留后面的数据,而不保存表头的情况,建议在保存到本地之后检查一下格式是否和下面是否相同
    在这里插入图片描述
  3. 相关代码
    # 获取相关数据
    def get_all_data(self):
        # 获取数据的时间段-结束时间
        end = datetime.date.today()  
        for code in self.codes:
            # 这个方法是pandas_datareader.data里面自带的,通过传入股票代码可以在相关网站获取对应数据
            stock = web.DataReader(code, "yahoo", self.in_date, end)
            # 将“Close”重命名为对应的code
            stock.rename(columns={"Close": code}, inplace=True)  
            stock[code].to_csv(self.path + code + ".csv")   # 保存到本地

获取本地的数据

将本地的数据获取到目前的程序里面来

    # 获取Excel中数据,并存到data列表中
    def get_data(self):
        # 直接将self.df初始化为第一支股票对应的数据,后面的数据只需要在这个基础上列相加就好了
        self.df = pd.read_csv(self.path + self.codes[0] + ".csv")
        # 通过循环获取所有的数据
        for code in self.codes[1:]:
            # 获取csv文件
            df = pd.read_csv(self.path + code + ".csv")
            # 数据合并
            self.df = pd.merge(self.df, df, left_on="Date", right_on="Date", how="outer")
        # 将索引设置为date
        self.df.set_index('Date', inplace=True)

获取某一天之前n天前的数据

这里的n是前面初始化的时候定义的time_span_inc与time_span_avg中更大的那个,为了在后续的处理中可以有充足的数据
获取的方法最好用切片,效率高也看起来方便,但是我的返回值时用的numpy,后面的操作基本上是根据numpy来的,所以懒得改了

    # 获取那n天的数据,格式是numpy
    def get_n_day(self, in_data):
        try:
            # 获取输入那天的位置索引
            position_index = self.df.index.get_loc(in_data)
            # 如果位置索引小于计算所需要的数字,那么说明数据量不够,
            if position_index>=max(self.time_span_avg, self.time_span_inc):
                # 用于保存每支股票的数据
                code_list = []
                for code in range(len(self.codes)):
                    # 用于保存当前股票的数据
                    i_list = []
                    for i in range(max(self.time_span_avg, self.time_span_inc)):
                        # 获取数据
                        i_list.append(self.df.iloc[position_index - i - 1, code])
                    code_list.append(i_list)
                # 这个地方应该要用切片来获取数据的,这么改虽然麻烦但是看得懂啊(其实就是懒得改了)
                return np.array(code_list)
            # 数据量不够,不能带入进行计算
            else:
                return np.array([0])
        except Exception as e:
            print("获取"+in_data+"的近日数据失败,估计这天没开盘,没有数据")
            return np.array([0])

获取涨幅与平均价格

在获取涨幅的时候,还顺便获取了涨幅最大的股票代码号的序列号

    # 计算涨幅
    def get_increase(self, result):
        inc = []
        for code in range(len(self.codes)):
            # 今天的价格/time_span_inc天前的价格 - 1
            increase = (result[code][0] / result[code][self.time_span_inc - 1]) - 1
            inc.append(increase)
        # 不仅仅获取了对应的涨幅,还获取了涨幅最大的股票代码号的序列号
        return inc, inc.index(max(inc))

    # 计算平均价格
    def get_avg(self, result):
        avg_result = result[:, :self.time_span_avg].mean(axis=1)
        return avg_result

模拟买卖

  1. 买的条件是判断现在的价格大于平均价格,涨幅最大而且要大于0
  2. 卖的条件是现在持有的股票不再是涨幅第一,或者现价小于近些天的平均价格
  3. 买卖的过程基本上就是重置手上持有的股票和持有的资金来完成的
1. 判断是买还是卖
    # 判断实行买卖
    def buy_sell(self, increase, avg, result):
        # 参考数据
        # ([0.05955, 0.02632, 0.058093], 0) 最后一个是涨幅最大的代码号
        # [1.68161 3.96707 5.50792]    这段时间的平均价格
        # [1.70799 4.01599 5.62799]    当前天的价格

        # 获取现在涨幅最大股票的价格和平均价格
        new_price = result[increase[1]]
        avg_price = avg[increase[1]]

        # 如果没有持有的股票则考虑买入
        if self.the_code["code"] is None:
            # 满足条件:现在的价格大于平均价格,涨幅最大而且要大于0
            if new_price > avg_price:
                self.buy(self.codes[increase[1]], new_price)

        # 如果现在持有的股票不再是涨幅第一,或者现价小于近些天的平均价,或者到了最后一天更新时间
        elif (self.the_code["code"] != self.codes[increase[1]]) | (new_price < avg_price) | (self.in_date == self.time):
            # 当天卖
            self.sell(result)
            # 当天卖,当天买
            if (new_price > avg_price) & (increase[0][increase[1]] > 0):
                self.buy(self.codes[increase[1]], new_price)
        else:
            print(self.in_date + "继续持有:", self.the_code["code"])
2. 卖
    def sell(self, result):
        # 因为卖出了,更新现有资金,并将现在持有的股票清空,用现在的价格/先前的价格再*现有的资金
        print("卖" + "*" * 30)
        print("在" + self.in_date + "卖出")
        print("全部卖出:", self.the_code["code"])

        # 卖出价格是持有股票(self.the_code["code"])的现价
        sell_price = result[self.codes.index(str(self.the_code["code"]))]
        print("卖出价格", sell_price)
        # 更新价格
        self.funds = self.funds * (sell_price / self.the_code["price"])
        self.change["funds"].append(self.funds)
        self.change["date"].append(self.in_date)
        self.the_code["code"] = None
        self.the_code["price"] = None

        print("资金持有变为:", self.funds)
        print("*" * 30)
3. 买
    def buy(self, code, new_price):
        # 更新持有股票和对应买入价格
        self.the_code["code"] = code
        self.the_code["price"] = new_price
        self.change["funds"].append(self.funds)
        self.change["date"].append(self.in_date)
        print("在" + self.in_date + "买入")
        print("将资金全部买入", self.the_code["code"])
        print("买入价格:", self.the_code["price"])
        print("资金持有变为:", self.funds)
        print("*" * 30)

后续辅助功能

  1. 将时间后推
    tim就是后推的天数
    没有返回值,直接操作in_date
    # 输入某天获取到第二天的str
    def get_next_day(self, tim=1):
        timeArray = time.strptime(self.in_date, "%Y-%m-%d")
        timeStamp = int(time.mktime(timeArray))
        timeStamp = timeStamp + 86400 * tim
        timeArray = time.localtime(timeStamp)
        self.in_date = time.strftime("%Y-%m-%d", timeArray)
  1. 画一个能看的图
    # 画图
    def draw(self):
        x = self.change["date"]
        y = self.change["funds"]
        # 设置图片大小
        plt.figure(figsize=(12, 8), dpi=80)
        # 绘图(折线)
        plt.plot(x, y, color="red", linewidth=2, alpha=0.6)
        # 设置轴的刻度
        plt.xticks(list(x)[::20], x[::20], rotation=45)  # rotation 为旋转角度
        # 展示图片
        plt.show()

最后的执行框架

  1. 获取本地数据
  2. 从第一天开始循环,将in_date后推
  3. 获取涨幅与平均价格
  4. 判断买卖,并实行
  5. 在循环结束之后输出现有的资金,和最大持有资金
  6. 画一个折线图反映变化
    # 主函数
    def the_main(self):
        self.get_data()
        while self.in_date != self.time:
            # 获取涨幅以及平均价格
            np_result = self.get_n_day(self.in_date)
            # 得确定获取的数据是非为空
            if np_result.any():
                increase = self.get_increase(np_result)
                # 再次确定获取的数据是非为空
                if increase != 0:
                    avg = self.get_avg(np_result)
                    # 进行买卖等操作
                    self.buy_sell(increase, avg, np_result[:, 0])
            # 进入下一天
            self.get_next_day()

        print("现在持有", self.funds)
        print(max(self.change["funds"]))
        self.draw()
画出来的图如下

在最后你持有了31973.95元
在这里插入图片描述

到此结束

最后附上全部代码

# -*- coding: utf-8 -*-
# 股票交易模拟

import datetime
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pandas_datareader.data as web


class try_day:
    def __init__(self, codes=[], in_date="2014-01-01", time=time.strftime('%Y-%m-%d', time.localtime(time.time())),
                 time_span_inc=13, time_span_avg=13, funds=100000, path="D:/"):
        self.codes = codes  # 所需要获取的股票
        self.in_date = in_date  # 数据处理开始日期
        self.time = time  # 数据处理结束日期
        self.time_span_inc = time_span_inc  # 涨幅跨度
        self.time_span_avg = time_span_avg  # 平均值跨度
        self.funds = funds  # 现有资金
        self.path = path  # 获取股票数据保存的地址

        self.df = None
        self.the_code = {"code": None, "price": None}
        self.change = {"funds": [], "date": []}

    # 获取相关数据
    def get_all_data(self):
        end = datetime.date.today()
        for code in self.codes:
            stock = web.DataReader(code, "yahoo", self.in_date, end)
            stock.rename(columns={"Close": code}, inplace=True)
            stock[code].to_csv(self.path + code + ".csv")  # 保存到本地

    # 获取Excel中数据,并存到data列表中
    def get_data(self):
        self.df = pd.read_csv(self.path + self.codes[0] + ".csv")
        for code in self.codes[1:]:
            df = pd.read_csv(self.path + code + ".csv")
            self.df = pd.merge(self.df, df, left_on="Date", right_on="Date", how="outer")
        self.df.set_index('Date', inplace=True)

    # 获取那n天的数据,格式是numpy
    def get_n_day(self, in_data):
        try:
            position_index = self.df.index.get_loc(in_data)
            if position_index >= max(self.time_span_avg, self.time_span_inc):
                code_list = []
                for code in range(len(self.codes)):
                    i_list = []
                    for i in range(max(self.time_span_avg, self.time_span_inc)):
                        i_list.append(self.df.iloc[position_index - i - 1, code])
                    code_list.append(i_list)
                return np.array(code_list)
            else:
                return np.array([0])
        except Exception as e:
            return np.array([0])

    # 计算涨幅
    def get_increase(self, result):
        inc = []
        for code in range(len(self.codes)):
            increase = (result[code][0] / result[code][self.time_span_inc - 1]) - 1
            inc.append(increase)
        return inc, inc.index(max(inc))

    # 计算平均价格
    def get_avg(self, result):
        avg_result = result[:, :self.time_span_avg].mean(axis=1)
        return avg_result

    # 判断实行买卖
    def buy_sell(self, increase, avg, result):
        new_price = result[increase[1]]
        avg_price = avg[increase[1]]
        if self.the_code["code"] is None:
            if new_price > avg_price:
                self.buy(self.codes[increase[1]], new_price)
        elif (self.the_code["code"] != self.codes[increase[1]]) | (new_price < avg_price) | (self.in_date == self.time):
            # 当天卖
            self.sell(result)
            # 当天卖,当天买
            if (new_price > avg_price) & (increase[0][increase[1]] > 0):
                self.buy(self.codes[increase[1]], new_price)
        else:
            print(self.in_date + "继续持有:", self.the_code["code"])

    def sell(self, result):
        print("卖" + "*" * 30)
        print("在" + self.in_date + "卖出")
        print("全部卖出:", self.the_code["code"])
        sell_price = result[self.codes.index(str(self.the_code["code"]))]
        print("卖出价格", sell_price)
        self.funds = self.funds * (sell_price / self.the_code["price"])
        self.change["funds"].append(self.funds)
        self.change["date"].append(self.in_date)

        self.the_code["code"] = None
        self.the_code["price"] = None

        print("资金持有变为:", self.funds)
        print("*" * 30)

    def buy(self, code, new_price):
        self.the_code["code"] = code
        self.the_code["price"] = new_price
        self.change["funds"].append(self.funds)
        self.change["date"].append(self.in_date)
        print("在" + self.in_date + "买入")
        print("将资金全部买入", self.the_code["code"])
        print("买入价格:", self.the_code["price"])
        print("资金持有变为:", self.funds)
        print("*" * 30)

    # 画图
    def draw(self):
        x = self.change["date"]
        y = self.change["funds"]
        plt.figure(figsize=(12, 8), dpi=80)
        plt.plot(x, y, color="red", linewidth=2, alpha=0.6)
        plt.xticks(list(x)[::20], x[::20], rotation=45)  # rotation 为旋转角度
        plt.show()

    # 主函数
    def the_main(self):
        self.get_data()
        while self.in_date != self.time:
            np_result = self.get_n_day(self.in_date)
            if np_result.any():
                increase = self.get_increase(np_result)
                if increase != 0:
                    avg = self.get_avg(np_result)
                    self.buy_sell(increase, avg, np_result[:, 0])
            # 进入下一天
            self.get_next_day()

        print("现在持有", self.funds)
        print(max(self.change["funds"]))
        self.draw()

    # 输入某天获取到第二天的str
    def get_next_day(self, tim=1):
        timeArray = time.strptime(self.in_date, "%Y-%m-%d")
        timeStamp = int(time.mktime(timeArray))
        timeStamp = timeStamp + 84600 * tim
        timeArray = time.localtime(timeStamp)
        self.in_date = time.strftime("%Y-%m-%d", timeArray)


if __name__ == '__main__':
    codes = ['159915.SZ', '510300.SS', '510500.SS']
    p = try_day(path="D:/", codes=codes, time='2019-12-31')
    # p.get_all_data()
    p.the_main()


发布了9 篇原创文章 · 获赞 1 · 访问量 1002

猜你喜欢

转载自blog.csdn.net/Alivorth/article/details/104525563