Python3 一些 Talib 没有的 Indicators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import pandas as pd
import numpy as np


# Pivot Points, Supports and Resistances
def PPSR(df):
    PP = pd.Series((df['High'] + df['Low'] + df['Close']) / 3)
    R1 = pd.Series(2 * PP - df['Low'])
    S1 = pd.Series(2 * PP - df['High'])
    R2 = pd.Series(PP + df['High'] - df['Low'])
    S2 = pd.Series(PP - df['High'] + df['Low'])
    R3 = pd.Series(df['High'] + 2 * (PP - df['Low']))
    S3 = pd.Series(df['Low'] - 2 * (df['High'] - PP))
    psr = {'PP':PP, 'R1':R1, 'S1':S1, 'R2':R2, 'S2':S2, 'R3':R3, 'S3':S3}
    PSR = pd.DataFrame(psr)
    df = df.join(PSR)
    return df


# Stochastic oscillator %K
def STOK(df):
    SOk = pd.Series((df['Close'] - df['Low']) / (df['High'] - df['Low']), name = 'SO%k')
    df = df.join(SOk)
    return df


# Stochastic Oscillator, EMA smoothing, nS = slowing (1 if no slowing)
def STO(df,  nK, nD, nS=1):
    SOk = pd.Series((df['Close'] - df['Low'].rolling(nK).min()) / (df['High'].rolling(nK).max() - df['Low'].rolling(nK).min()), name = 'SO%k'+str(nK))
    SOd = pd.Series(SOk.ewm(ignore_na=False, span=nD, min_periods=nD-1, adjust=True).mean(), name = 'SO%d'+str(nD))
    SOk = SOk.ewm(ignore_na=False, span=nS, min_periods=nS-1, adjust=True).mean()
    SOd = SOd.ewm(ignore_na=False, span=nS, min_periods=nS-1, adjust=True).mean()
    df = df.join(SOk)
    df = df.join(SOd)
    return df


# Stochastic Oscillator, SMA smoothing, nS = slowing (1 if no slowing)
def STO(df, nK, nD,  nS=1):
    SOk = pd.Series((df['Close'] - df['Low'].rolling(nK).min()) / (df['High'].rolling(nK).max() - df['Low'].rolling(nK).min()), name = 'SO%k'+str(nK))
    SOd = pd.Series(SOk.rolling(window=nD, center=False).mean(), name = 'SO%d'+str(nD))
    SOk = SOk.rolling(window=nS, center=False).mean()
    SOd = SOd.rolling(window=nS, center=False).mean()
    df = df.join(SOk)
    df = df.join(SOd)
    return df


# Mass Index
def MassI(df):
    Range = df['High'] - df['Low']
    EX1 = pd.ewma(Range, span = 9, min_periods = 8)
    EX2 = pd.ewma(EX1, span = 9, min_periods = 8)
    Mass = EX1 / EX2
    MassI = pd.Series(pd.rolling_sum(Mass, 25), name = 'Mass Index')
    df = df.join(MassI)
    return df


# Vortex Indicator: http://www.vortexindicator.com/VFX_VORTEX.PDF
def Vortex(df, n):
    i = 0
    TR = [0]
    while i < df.index[-1]:
        Range = max(df.get_value(i + 1, 'High'), df.get_value(i, 'Close')) - min(df.get_value(i + 1, 'Low'), df.get_value(i, 'Close'))
        TR.append(Range)
        i = i + 1
    i = 0
    VM = [0]
    while i < df.index[-1]:
        Range = abs(df.get_value(i + 1, 'High') - df.get_value(i, 'Low')) - abs(df.get_value(i + 1, 'Low') - df.get_value(i, 'High'))
        VM.append(Range)
        i = i + 1
    VI = pd.Series(pd.rolling_sum(pd.Series(VM), n) / pd.rolling_sum(pd.Series(TR), n), name = 'Vortex_' + str(n))
    df = df.join(VI)
    return df


# KST Oscillator
def KST(df, r1, r2, r3, r4, n1, n2, n3, n4):
    M = df['Close'].diff(r1 - 1)
    N = df['Close'].shift(r1 - 1)
    ROC1 = M / N
    M = df['Close'].diff(r2 - 1)
    N = df['Close'].shift(r2 - 1)
    ROC2 = M / N
    M = df['Close'].diff(r3 - 1)
    N = df['Close'].shift(r3 - 1)
    ROC3 = M / N
    M = df['Close'].diff(r4 - 1)
    N = df['Close'].shift(r4 - 1)
    ROC4 = M / N
    KST = pd.Series(pd.rolling_sum(ROC1, n1) + pd.rolling_sum(ROC2, n2) * 2 + pd.rolling_sum(ROC3, n3) * 3 + pd.rolling_sum(ROC4, n4) * 4, name = 'KST_' + str(r1) + '_' + str(r2) + '_' + str(r3) + '_' + str(r4) + '_' + str(n1) + '_' + str(n2) + '_' + str(n3) + '_' + str(n4))
    df = df.join(KST)
    return df


# True Strength Index
def TSI(df, r, s):
    M = pd.Series(df['Close'].diff(1))
    aM = abs(M)
    EMA1 = pd.Series(pd.ewma(M, span = r, min_periods = r - 1))
    aEMA1 = pd.Series(pd.ewma(aM, span = r, min_periods = r - 1))
    EMA2 = pd.Series(pd.ewma(EMA1, span = s, min_periods = s - 1))
    aEMA2 = pd.Series(pd.ewma(aEMA1, span = s, min_periods = s - 1))
    TSI = pd.Series(EMA2 / aEMA2, name = 'TSI_' + str(r) + '_' + str(s))
    df = df.join(TSI)
    return df


# Accumulation/Distribution
def ACCDIST(df, n):
    ad = (2 * df['Close'] - df['High'] - df['Low']) / (df['High'] - df['Low']) * df['Volume']
    M = ad.diff(n - 1)
    N = ad.shift(n - 1)
    ROC = M / N
    AD = pd.Series(ROC, name = 'Acc/Dist_ROC_' + str(n))
    df = df.join(AD)
    return df


# Force Index
def FORCE(df, n):
    F = pd.Series(df['Close'].diff(n) * df['Volume'].diff(n), name = 'Force_' + str(n))
    df = df.join(F)
    return df


# Ease of Movement
def EOM(df, n):
    EoM = (df['High'].diff(1) + df['Low'].diff(1)) * (df['High'] - df['Low']) / (2 * df['Volume'])
    Eom_ma = pd.Series(pd.rolling_mean(EoM, n), name = 'EoM_' + str(n))
    df = df.join(Eom_ma)
    return df


# Coppock Curve
def COPP(df, n):
    M = df['Close'].diff(int(n * 11 / 10) - 1)
    N = df['Close'].shift(int(n * 11 / 10) - 1)
    ROC1 = M / N
    M = df['Close'].diff(int(n * 14 / 10) - 1)
    N = df['Close'].shift(int(n * 14 / 10) - 1)
    ROC2 = M / N
    Copp = pd.Series(pd.ewma(ROC1 + ROC2, span = n, min_periods = n), name = 'Copp_' + str(n))
    df = df.join(Copp)
    return df


# Keltner Channel
def KELCH(df, n):
    KelChM = pd.Series(pd.rolling_mean((df['High'] + df['Low'] + df['Close']) / 3, n), name = 'KelChM_' + str(n))
    KelChU = pd.Series(pd.rolling_mean((4 * df['High'] - 2 * df['Low'] + df['Close']) / 3, n), name = 'KelChU_' + str(n))
    KelChD = pd.Series(pd.rolling_mean((-2 * df['High'] + 4 * df['Low'] + df['Close']) / 3, n), name = 'KelChD_' + str(n))
    df = df.join(KelChM)
    df = df.join(KelChU)
    df = df.join(KelChD)
    return df


# Donchian Channel
def DONCH(low, high, timeperiod: int = 20):
    if len(high) != len(low):
        return [], []
    dc_low = []
    dc_high = []
    for i in range(0, len(high)):
        if i < timeperiod - 1:
            dc_low.append(np.nan)
            dc_high.append(np.nan)
        else:
            min_list = low.ix[i - (timeperiod - 1): i]
            max_list = high.ix[i - (timeperiod - 1): i]
            if len(min_list) == 0 or len(max_list) == 0:
                dc_low.append(np.nan)
                dc_high.append(np.nan)
            else:
                dc_min = min(min_list)
                dc_max = max(max_list)
                dc_low.append(dc_min)
                dc_high.append(dc_max)
    return dc_low, dc_high

人,经济与国家 读书笔记

第一章 人的行动的基本原理

第二章 直接交换

  1. 投机和供求表

  2. 库存和总持有需求

  3. 价格低时,市场的总需求提升;价格高时,市场的总需求降低

  4. 市场会自行发现一个均衡价格,使得总库存需求等于总需求

  5. 连续的市场与价格的变动

  6. 大型市场中,打到均衡价格的速度快,投机行为趋向于改善对均衡点的预期,使均衡点快速到来

  7. 市场的单一属性改变:
    1. 需求表增加,供给表不变,新的均衡价格更高,新的均衡状态下发生的交易量比旧的更多,价格上升,交易量上升
    2. 和1相反,需求增加供给不变,价格下降,交易量下降
    3. 供给表上升,需求表不变,人们愿意从库存中处理更多的库存,新的均衡价格比旧的更低,均衡交易量更多,价格下降,交易量上升
    4. 和3相反,供给下降,需求不变,价格上升,交易量下降
    5. 总结一下,需求和供给都和交易量正相关,需求和价格正相关,供给和价格负相关

Install Manjaro From macOS

从 macOS 10.14 制作安装 U 盘

下载好 iso 之后,将 iso 改名为 ~/Downloads/manjaro-kde.iso,然后将 iso 转换成 dmg:

1
hdiutil convert -format UDRW -o ~/Downloads/manjaro ~/Downloads/manjaro-kde.iso

看一下 U 盘是 disk几:

1
diskutil list

假设 U 盘是 disk9,分区,unmount,再写入镜像:

1
2
3
diskutil partitionDisk disk9 1 GPT HFS+ newdisk R
diskutil unmountDisk /dev/disk9
sudo dd if=/Users/openthread/Downloads/manjaro.dmg of=/dev/rdisk9 bs=1m

U盘插到 pc,重启,安装

Read on →

JDK 和 Maven macOS 的安装与配置

JDK

下载安装

https://www.oracle.com/technetwork/java/javase/downloads/index.html 下载想用的 jdk 版本,需要登录。

下载好以后双击 dmg 安装。

命令行输入 java -version 查看版本。

配置 JAVA_HOME 环境变量

安装包没自动配置环境变量,可能是考虑宿主机多个不同 jdk 版本,没替用户做决定,需要手动配置一下。

Read on →

Python/Numpy 性能优化

Cython

将 Python 翻译成 c/c++ 再编译执行。
比原生 Python 快 1.5 倍左右。
缺点是要写个 makefile

pypy

优点是无需像 cython 一样需要修改代码,写 makefile 和 main,缺点是有些三方库不支持。

安装:

1
brew install pypy3

然后安装 pypy pip。注意 pypy pip 不支持 socks5 代理,可能需要关闭或指定 http 代理:

1
2
3
4
pypy3 -m ensurepip
export ALL_PROXY=
pypy3 -m pip install pip --upgrade
pypy3 -m pip install setuptools --upgrade

将 pypy3 path 加入 $PATH 不然安装 tables 的时候报 warning:

1
export PATH=$PATH:/usr/local/share/pypy3

安装依赖(举点例子):

1
2
3
4
5
6
7
8
pypy3 -m pip install numpy
pypy3 -m pip install TA-Lib
pypy3 -m pip install requests
pypy3 -m pip install ccxt
pypy3 -m pip install tables
pypy3 -m pip install matplotlib
pypy3 -m pip install coloredlogs
pypy3 -m pip install pandas

如果 macOS 遇到 pypy 安装 numpy 时提示:

1
2
3
4
Checking for cc... ld: library not found for -lgcc_s.10.4
clang: error: linker command failed with exit code 1 (use -v to see invocation)
...
RuntimeError: Broken toolchain: cannot link a simple C program

尝试下面命令后再次重试安装 numpy:

1
2
3
cd /usr/local/lib
sudo ln -s ../../lib/libSystem.B.dylib libgcc_s.10.4.dylib
cd -

Numpy

比原生 Python 快 10 倍左右。

numexpr

1
2
3
4
5
6
import numpy as np
import numexpr as ne
N = 10 ** 5
a = np.random.uniform(-1, 1, N)
b = np.random.uniform(-1, 1, N)
ne.evaluate('a ** 2 + b ** 2')

比 Numpy 快 2 到 10 倍。

Read on →

利用pandas进行数据分析第二版 笔记

先放书的链接: https://www.amazon.cn/dp/B07G2PK49V

Read on →

iPhone Popover Above iOS9

直接上图上代码。。。

OTPopoverMenuViewController.h:

1
2
3
4
5
6
7
8
9
10
@interface OTPopoverMenuViewController : UIViewController

- (void)presentInController:(UIViewController *)controller
                 sourceView:(UIView *)view;

- (void)presentInController:(UIViewController *)controller
              barButtonItem:(UIBarButtonItem *)barButtonItem;


@end
Read on →

评价基金性能的常用指标

最大回撤(Max Draw Down)

最大回撤为:在选定周期内任一历史时点往后推,产品净值走到最低点时的收益率回撤幅度的最大值。

其计算的时间复杂度是O(n)的。有些O(n2)的写法比较业余。

python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_max_draw_down(in_list: list):
    dd_list = []
    max_so_far = in_list[0]
    for i in range(len(in_list)):
        if in_list[i] > max_so_far:
            dd = 0
            dd_list.append(dd)
            max_so_far = in_list[i]
        else:
            current = in_list[i]
            dd = (max_so_far - current) / max_so_far
            dd_list.append(dd)
    mdd = max(dd_list)
    return mdd

夏普比率(Sharpe Ratio)

评价单位承担的风险可以取得多少正向收益。在同种时间跨度下,越高越好。

计算方法:

  • 平均收益率超过无风险收益率的部分除以收益率的标准差。
  • 如果通过高频夏普率(比如1d)推测低频夏普率(一般是年),若每年有255个交易日,一般是再乘上根号下255。像币圈高频夏普率(4h)推导年,则是再乘上根号下 365 * 24 / 4。

    缺陷:

  • 由于标准差是正值,所以无法区分上行风险和下行风险。

    优点:

  • 国内外知名度高。

附两个知乎的讲解链接:
夏普率越高越好吗? - 石川的回答 - 知乎
求问基金风险指标的计算:夏普比率,索提诺比率,阿尔法系数等? - 财小鲸之秦岭的回答 - 知乎

1
2
3
4
5
import numpy

def sharpe_ratio(returns, risk_free_rate=0.0):
    mean = numpy.mean(returns)
    return (mean - risk_free_rate) / numpy.std(returns)

其中 returns 为每条 ohlc 的变化率,比如 [0.02, 0.03, -0.03, …]
risk_free_rate 为每条 ohlc 的无风险收益率。比如okex余币宝年化1%,传入的是4小时returns,这里应该传入 1% / (365 * 24 / 4)

可以通过历史净值列表(equity)生成 returns:

1
2
3
4
5
def returns_from_equity(in_equity: list):
    returns_np = numpy.array(in_equity)
    returns_np = returns_np[1:] / returns_np[:-1]
    returns_np = returns_np - 1
    return returns_np

然后把返回值代入下一步计算。

Read on →

Python Talib 的一些基础用法

首先还是导入一些业界标准库:

1
2
3
import pandas as pd
import numpy as np
import talib as ta

计算RSI

1
2
close = np.array(bars.close)
print(ta.RSI(close))  # 默认15根bars

计算MA

1
ta.MA(close)  # 默认 30 根 bars,即 MA30

设置计算用的时长,比如计算 MA5

1
ta.MA(close, timeperiod=5)

计算 EMA11 和 EMA22

1
2
ta.EMA(close, timeperiod=11)
ta.EMA(close, timeperiod=22)

全部指标和方法列表

http://mrjbq7.github.io/ta-lib/funcs.html

Pandas的一些基础用法

首先我们导入一些‘业界标准’库

1
2
3
4
import pandas as pd
import numpy as np
import talib as ta
import matplotlib.pyplot as plt

Pandas 里有两种常用的结构,一种叫DataFrame,作为二维的一张表格;另一种叫Series,是一维数组。
DataFrame取单行和单列得到的都是Series类型的对象。

追加数据

1
df = df.append(series, ignore_index=True)

获取最后一列数据

1
series = df.iloc[-1]

按行遍历

1
2
for i in df.index:
    print(df.iloc[i])

前十行组成子DataFrame

1
2
for i in df.index:
    print(df.iloc[0:10])  # 含下标0到9的元素,不含下标10的元素

获取名为 close 的 column

1
2
3
series = df.close
或者
series = df['close']
Read on →