• Python数据分析--Numpy常用函数介绍(6)--Numpy中与股票成交量有关的计算


            成交量(volume)是投资中一个非常重要的变量,它是指在某一时段内具体的交易数,可以在分时图中绘制,包括日线图、周线图、月线图甚至是5分钟、30分钟、60分钟图中绘制。

      股票市场成交量的变化反映了资金进出市场的情况,成交量是判断市场走势的重要指标。一般情况下,成交量大且价格上涨的股票,趋势向好。成交量持续低迷时,一般出现在熊市或股票整理阶段,市场交易不活跃。成交量是判断股票走势的重要依据,对分析主力行为提供了重要的依据。投资者对成交量异常波动的股票应当密切关注。

      OBV(On-Balance Volume,净额成交量或叫能量潮指标)是最简单的股价指标之一,它可以由当日收盘价、前一天的收盘价以及当日成交量计算得出。以前一日为基期计算当日的OBV值(可以认为基期的OBV值为0)。若当日收盘价高于前一日收盘价,则本日OBV等于基期OBV加上日成交量。若当日收盘价低于前一日收盘价,则本日OBV等于基期OBV减去当日成交量。若当日收盘价相比前一日没有变化,则当日成交量以0计算。

    一、OBV计算

      鉴于上述计算方法,需要在成交量前面乘上一个由收盘价变化决定的正负号(收盘价低于前一交易日收盘价,负号,收盘价高于前一交易日收盘价,正号)。在本篇中,学习该问题的两种解决方法,一种是使用NumPy中的 sign 函数,另一种是使用NumPy的piecewise 函数。

    1) 把数据分别加载到收盘价和成交量的数组中:

    close,vol = np.loadtxt('data036.csv',delimiter=',', usecols=(5,6),converters={1:datestr2num},unpack=True)

    data036.csv中的第6列和第7列分别为收盘价和当日成交量。

    前篇介绍过numpy.diff()可以计算相邻的差(即上述收盘价close的差值),并利用这个差值, 用sign 函数计算正负号

    changes = np.diff(close)
    signs = np.sign(changes)
    print ("Signs", signs)

    运行结果:

    Signs [-1. -1. -1. -1.  1.  1.  1. -1.  1.  1.  1. -1.  1. -1. -1. -1. -1.  1.
      1. -1. -1.  1.  1.  1.  1.  1.  1.  1. -1.  1.  1.  1. -1. -1. -1.  1.
     -1.  1.  1.  1. -1. -1.  1.  1.  1. -1. -1.  1.  1.  1.  1.  1.  1. -1....

    2)也可以使用 piecewise 函数来获取数组元素的正负。 piecewise函数可以分段给定取值。使用合适的返回值和对应的条件调用该函数:

    pieces = np.piecewise(changes, [changes < 0, changes > 0], [-1, 1])
    print("Pieces", pieces)

    3)判断是否 sign 函数和piecewise 函数计算结果是否一致用array_equal()函数:

    print ("Arrays equal?", np.array_equal(signs, pieces))

    运行结果:

    Arrays equal? True

    4)由于diff()y计算的结果是相邻数据相减,因此得到419个数据,较从文件中导入的数据420个少一位,因此无法计算首日的OBV值

    obv_values = vol[1:] * signs          #计算obv值
    print("obv values:",obv_values[:20]) #打印前20个obv值

    完成代码如下:

    复制代码
    import numpy as np
    from datetime import datetime
    import matplotlib.pyplot as plt
    import sys,os
    
    def datestr2num(s): #定义一个函数
        return datetime.strptime(s.decode('ascii'),"%Y-%m-%d").date().weekday()
    
    close,vol = np.loadtxt('data036.csv',delimiter=',', usecols=(5,6),converters={1:datestr2num},unpack=True)
    #new_close = np.loadtxt('data999.csv',delimiter=',', usecols=(5,),converters={1:datestr2num},unpack=True)
    
    changes = np.diff(close)
    signs = np.sign(changes)
    print ("Signs", signs[:20])#打印前20个signs值
    
    pieces = np.piecewise(changes, [changes < 0, changes > 0], [-1, 1])
    print("Pieces", pieces[:20])#打印前20个pieces值
    print ("Arrays equal?", np.array_equal(signs, pieces))
    
    obv_values = vol[1:] * signs          #计算obv值
    print("obv values:",obv_values[:20]) #打印前20个obv值
    复制代码

    运行结果:

    二、 计算单个交易日的利润

    1)读入数据

    将所有交易数据(开盘价、收盘价、最高价、最低价,成交量等)加载到对应的数组中

    复制代码
    import numpy as np
    from datetime import datetime
    import matplotlib.pyplot as plt
    import sys,os
    
    def datestr2num(s): #定义一个函数
        return datetime.strptime(s.decode('ascii'),"%Y-%m-%d").date().weekday()
    
    opens,highs,lows,closes,vols = np.loadtxt('data036.csv',delimiter=',', usecols=(2,3,4,5,6),converters={1:datestr2num},unpack=True) #开盘价、最高价、最低价、收盘价、成交量数组。
    复制代码

    2)调用 vectorize 函数并给定calc_profit 函数作为参数:

    (1)先定义一个计算利润的函数:这个函数,是以开盘价买入,以当日收盘价卖出,所获得的利润即买入和卖出的差价。事实上,计算相对利润更为直观。

    def calc_profit(opens, highs, lows, closes):
        buy = opens * 1
        if lows < buy < highs :
            return (closes - buy)/buy
        else:
            return 0

    (2)调用 vectorize 函数并给定calc_profit 函数作为参数

    func = np.vectorize(calc_profit)
    profits=func(opens,highs,lows,closes)
    
    print ("Profits", profits)

    3)选择非零利润的交易日,并计算平均值:

    real_trades = profits[profits != 0]
    print ("Number of trades", len(real_trades), round(100.0 * len(real_trades)/len(closes), 2),"%")
    print ("Average profit/loss %", round(np.mean(real_trades) * 100, 2))

    当然也可以分别计算盈利和亏损:

    复制代码
    real_trades = profits[profits > 0]
    print ("Number of trades", len(real_trades), round(100.0 * len(real_trades)/len(closes), 2),"%")
    print ("平均盈利: %", round(np.mean(real_trades) * 100, 2))
    
    loss_trades = profits[profits < 0]
    print ("Number of trades", len(loss_trades), round(100.0 * len(loss_trades)/len(closes), 2),"%")
    print ("平均亏损 %", round(np.mean(loss_trades) * 100, 2))
    复制代码

    实际运行结果:

    三、数据平滑

    噪声数据很难处理,因此需要对其进行平滑处理,除前篇介绍的计算移动平均线的方法,还可以使用NumPy中的一个函数来平滑数据。hanning 函数是一个加权余弦的窗函数。
    1)调用 hanning 函数计算权重,生成一个长度为 N 的窗口(在这个示例中 N 取8)

    N=8
    weights = np.hanning(N)  #调用hanning 函数计算权重,生成一个长度为8的窗口
    print("Weights", weights)

    运行结果:

    Weights [0.         0.1882551  0.61126047 0.95048443 0.95048443 0.61126047 0.1882551  0.        ]

    2)用 convolve 函数计算closes的股票收益率,以归一化处理后的 weights 作为参数

    复制代码

    closes_returns = np.diff(closes) / closes[ : -1] #计算收盘价相邻差价
    smooth_closes = np.convolve(weights/weights.sum(), closes_returns) [N-1:-N+1]#利用权重,计算数据平滑
    opens_returns = np.diff(opens) / opens[ : -1] #计算开盘价相邻差价
    smooth_opens = np.convolve(weights/weights.sum(), opens_returns) [N-1:-N+1]

    复制代码

    3)用 Matplotlib 绘图

    复制代码

    t = np.arange(N - 1, len(closes_returns))
    plt.plot(t, closes_returns[N-1:], lw=1.0)
    plt.plot(t, smooth_closes, lw=2.0)
    plt.plot(t, opens_returns[N-1:], lw=1.0)
    plt.plot(t, smooth_opens, lw=2.0)
    plt.show()

    复制代码

    运行结果:

    4)

    如上图中的折线有交叉,这些交叉点可能就是股价趋势的转折点,至少可以表明closes和opens之间的股价关系发生了变化,这些转折点可能会经常出现,可以利用它们预测未来的股价走势。

    使用多项式拟合平滑后两组数据,解出的两个多项式取值相等时(即在哪些地方存在交叉点),这等价于先对两个多项式函数作差,然后对所得的多项式函数求根。使用 polysub 函数对多项式作差如下:

    t = np.arange(N - 1, len(closes_returns))
    poly_closes = np.polyfit(t, smooth_closes,N) #求收盘价的多项式
    poly_opens = np.polyfit(t, smooth_opens, N)  #求收盘价的多项式
    poly_sub = np.polysub(poly_closes, poly_opens)  #polysub函数对多项式作差,
    xpoints = np.roots(poly_sub)    #对所得的多项式函数求根
    print("Intersection points:", xpoints)

    运行结果:

    Intersection points: [403.82451866 354.50031142 289.94335284 213.44012464 185.82581983
      97.72837787  51.03724424  18.28586259]

    5)用 isreal 函数来判断数组元素是否为实数,用 select 函数选出它们。 select 函数可根据一组给定的条件,从一组元素中挑选出符合条件的元素并返回数组。

    得到的实数交叉点、再去掉其中为0的元素。 trim_zeros 函数可以去掉一维数组中开头和末尾为0的元素。

    复制代码
    reals = np.isreal(xpoints)  #用isreal 函数来判断数组元素是否为实数
    print ("Real number:", reals)
    
    xpoints = np.select([reals], [xpoints]) #select 函数根据一组给定条件,
    xpoints = xpoints.real # 从一组元素中挑选出符合条件的元素并返回数组
    print("Real intersection points:", xpoints)
    print("Sans 0s:", np.trim_zeros(xpoints))#trim_zeros 函数可以去掉一维数组中开头和末尾为0的元素
    复制代码

    运行结果如下:

    复制代码
    Intersection points: [403.82451866 354.50031142 289.94335284 213.44012464 185.82581983
      97.72837787  51.03724424  18.28586259]
    Real number: [ True  True  True  True  True  True  True  True]
    Real intersection points: [403.82451866 354.50031142 289.94335284 213.44012464 185.82581983
      97.72837787  51.03724424  18.28586259]
    Sans 0s: [403.82451866 354.50031142 289.94335284 213.44012464 185.82581983
      97.72837787  51.03724424  18.28586259]
    复制代码

    完整代码如下:

    复制代码
    import numpy as np
    from datetime import datetime
    import matplotlib.pyplot as plt
    
    def datestr2num(s): #定义一个函数
        return datetime.strptime(s.decode('ascii'),"%Y-%m-%d").date().weekday()
    
    opens,highs,lows,closes,vols = np.loadtxt('data036.csv',delimiter=',', usecols=(2,3,4,5,6),converters={1:datestr2num},unpack=True)
    #开盘价、最高价、最低价、收盘价、成交量数组。
    N=8
    weights = np.hanning(N)  #调用hanning 函数计算权重,生成一个长度为8的窗口
    print("Weights:", weights)
    closes_returns = np.diff(closes) / closes[ : -1] #计算收盘价相邻差价
    smooth_closes = np.convolve(weights/weights.sum(), closes_returns) [N-1:-N+1]#利用权重,计算数据平滑
    opens_returns = np.diff(opens) / opens[ : -1]    #计算开盘价相邻差价
    smooth_opens = np.convolve(weights/weights.sum(), opens_returns) [N-1:-N+1]
    t = np.arange(N - 1, len(closes_returns))
    
    #多项式拟合平滑后的数据
    t = np.arange(N - 1, len(closes_returns))
    poly_closes = np.polyfit(t, smooth_closes,N) #求收盘价的多项式
    poly_opens = np.polyfit(t, smooth_opens, N)  #求收盘价的多项式
    poly_sub = np.polysub(poly_closes, poly_opens)  #polysub函数对多项式作差,
    xpoints = np.roots(poly_sub)    #对所得的多项式函数求根
    print("Intersection points:", xpoints)
    
    reals = np.isreal(xpoints)  #用isreal 函数来判断数组元素是否为实数
    print ("Real number:", reals)
    xpoints = np.select([reals], [xpoints]) #select 函数根据一组给定条件,
    xpoints = xpoints.real # 从一组元素中挑选出符合条件的元素并返回数组
    print("Real intersection points:", xpoints)
    print("Sans 0s:", np.trim_zeros(xpoints))#trim_zeros 函数可以去掉一维数组中开头和末尾为0的元素
    
    plt.plot(t, closes_returns[N-1:], lw=1.0)
    plt.plot(t, smooth_closes, lw=2.0)
    plt.plot(t, opens_returns[N-1:], lw=1.0)
    plt.plot(t, smooth_opens, lw=2.0)
    plt.show()
    复制代码

     

  • 相关阅读:
    线性代数学习笔记8-2:对称矩阵和Hermitian矩阵、共轭转置、正定矩阵
    国产5G手机20天销量不及苹果一天,被iPhone15按在地上摩擦
    人体神经的作用与功能,人的神经系统的作用
    Dubbo 面试题(三)
    学生HTML个人网页作业作品 (水果商城HTML+CSS)
    JDBC整合C3P0,DBCP,DRUID数据库连接池
    go语言 leetcod1 两数之和
    2 万字详解,彻底讲透 Elasticsearch
    代码随想录1刷—字符串篇
    Python最常用的库
  • 原文地址:https://www.cnblogs.com/codingchen/p/16350679.html