一、量化思想:
赌球:如果你是赌球老板,如何赚1个亿的小目标
二、量化交易
量化交易是指以先进的数学模型替代人为的主观判断,利用计算机技术从庞大的历史数据中海选能带来超额收益的多种“大”事件以制定策略,极大地减少了投资者情绪波动的影响,在市场极度狂热或悲观的情况下作出非理性的投资决策
三、量化交易知识树
1、金融学:金融工程、金融衍生品、会计学
2、数学:概率论、统计学、博弈论
3、计算机技术:计算机编程、机器学习、大数据
四、量化交易、主观交易
五、量化交易流程
1、数据获取
2、数据清洗
3、策略编写
4、策略回测
5、策略优化
6、模拟盘交易【半年到1年】
7、实盘交易
六、量化交易分类:
1、交易产品:股票策略、CTA策略、期权策略、FOF策略
2、盈利模式:
① 单边多空策略
② 套利策略:赌球老板策略
③ 对冲策略
3、策略信号:
① 多因子策略
② 均值回归策略
③ 动量效益策略:波浪、动能
④ 二八轮动策略:20%的股票带动股指
⑤ 海龟策略:非常有限的范围波动
⑥ 机器学习策略
七、量化交易总体开发流程
(一)数据获取:
内容:
1、行情数据
2、宏观数据
3、财务数据
4、舆情数据
方式:
网站下载
客户端
三方API
爬虫
(二)数据清洗:
场景:
垃圾数据清除
空值填充
格式转换
数据对齐
类库:
Numpy:科学计算
pandas:时间序列处理
(三)策略编写:
信号捕捉、交易(建仓、平仓)
(四)策略回测:
回测参数设置、策略实例化、历史数据载入、回测执行、计算盈亏、计算统计指标、生成回测报告
(五)策略优化:
重视交易费、重视风险,重视退出、优化无止境
(六)模拟盘交易:
过去表现并不表示未来结果
至少半年以上
模拟盘稳定收益100%以上再考虑实盘交易
(七)实盘交易
做好第一年会输的准备
不急于扩大投资,增加杠杆
心态最重要
八、量化交易分类-交易产品:
(一)交易产品
1、股票策略:股票
股票:股价公司为筹集资金而发行给各个股东作为持股凭证并取得股息和红利的一种有价证券
2、期权策略:期权
一种选择权,是一种能在未来某特定时间以特定价格买卖一定数量的某周特定商品的权利
盈利模式:期权合约差价(常用)、到期权收益
3、CTA策略:期货
一种标准化合约,期货交易所统一制定的、约定在未来的某一个确定的日期和地点按照约定的条件买卖一定数量和质量的标的资产的标准化合约
盈利模式:关注价格趋势获取利差
4、FOF策略:FOF
基金中基金,是一种专门投资于其他投资基金的基金
(二)盈利模式
1、单边多空策略
低价买进,待股价出现单边下跌时卖出,赚取利差
通过单边买入或者单边卖出实现盈利
2、套利策略
在金融市场利用某些金融产品价格与收益率暂时不一致的机会获得收益的策略
追求无风险套利,即价格变动所产生的无风险收益
3、对冲策略:
指特意降低另一项投资风险的投资。同时进行两笔行情相关、方向相反、数据量相当、盈亏相抵的交易
在期货股票市场和股票市场同时进行等量反向交易,以锁定既得利益(或成本),通过抵消两个市场的损益来规避股票市场的系统性风险
做多同时做空,市场向上,赚钱;市场向下,赚钱或少亏钱
(三)策略信号
1、策略信号分类:
多因子:
交易模型:
机器学习:
2、策略信号:
交易信号,买入或卖出的一系列特征
3、多因子策略:
找到某个和收益率最相关的指标,并根据该指标,建一个股票组合,期望该组合在未来的一段时间跑赢或跑输指数
跑赢指数,做多;跑输指数,做空
4、交易模型:
基于现代多学科众多理论,以及多种金融技术分析理论,具有普遍性,可盈利可量化可执行交易系统
市场趋势符合交易模型即可盈利
高频量化交易模型:
5、机器学习:
从大量数据中找到某种规律,包括但不局限于文本数据、图像数据等,找到可盈利,可量化,可执行的策略信号
区别于传统金融量化策略,从更丰富的数据维度中识别策略信号
九、股票基本概念:
1、股票投资好处:
分红、送股配股、交易收益、本金少、易变现、避免货币贬值
2、风险和收益
3、股票的分类
风险与收益:
蓝筹股:
经营业绩长期稳定增长的大公司,一般时各个行业的龙头企业,市值在5000亿以上,不管行业景气不景气都能转到钱,一般都有较稳定的现金分红
代表:茅台
白马股:
长期业绩稳定、业绩成长性高,有较强的分配能力、分红不错,市值在3000亿以下,一般集中在消费领域
代表:海尔智家
成长股:
成长性高于白马股,公司正处于高速发展的阶段,业绩增长远超整个行业,一般为有发展前景的中小公司,以高新技术和科技类的为主
代表:东方财富
周期股:
业绩随经济周期波动明显,多为工业基础原材料的大宗商品,机械、造船等制造业,港口、远洋运输等航运业以及汽车、房地产这样的非生活必需品行业
代表:万科
概念股:
具有某种特别内涵的股票,这一内涵通常会被当作一种选股和炒作题材,成为股市的热点
元宇宙概念股:宋城演艺
十、股票行业分类:
1、 股票行业分类:
中证行业分类:中证行业分类标准由中证指数公司2007年开始正式发布,现行版本为2021年12月修订。中证行业分类标准相对“官方”,更接近监管行业分类,并同国际接轨
申万行业分类:申万行业分类标准由申万宏源研究所发布,现行版本为2021年8月修订。申万行业分类标准相对“务实”,更加接近中国行业国情特征
2、中证行业分类:
中证行业分类标准划分为四级,分别为一级、二级、三级和四级行业分类;分为11个一级行业、35个二级行业、90余个三级行业及200余个四级行业
中证行业分类:
https://www.csindex.com.cn/#/indices/family/list?indexseries=2&custom=0&sharelndex=18
3、申万行业分类:
申万行业分类标准划分为三级,分别为一级、二级和三级行业分类;申万行业分类分为31个一级行业、134个二级行业和346个三级行业
申万行业分类链接:https://www.swsresearch.com/institute_sw/allIndex/downloadCenter/industryType
4、股票行业分类作用:
持续盈利:最近二十年内持续盈利,食品饮料与医药生物行业
传统行业:前十年表现出色,后十年表现不佳,电气设备、采掘、有色金属、传统汽车、机械设备、钢铁
新兴行业:前十年不怎么样,最近十年表现出色,计算机、电子、新能源、家电
5、表现不佳:
最近二十年内缺乏盈利表现,公用事业、纺织服务
十一、影响股价因素
1、股价:股票的交易价格,与股票的价值是相对的概念。股票价值的真实含义是企业资产的价值。而股价的价值就是每股收益乘以市盈率
2、影响因素:经济因素、政治因素、行业因素、企业自身因素、市场因素、心理因素
3、经济因素:
主要指经济周期因素,经济衰退,股价随之下跌;经济繁荣,股价也随之上涨
美国经济周期与金融周期对照
阴影部分为美国经济紧缩时期
4、政治因素:
外交的改善会使有关跨国公司股价上升;
战争使各国政治经济不稳,股价下跌,但会使军工行业股价上升
① 历次战争对标普500的影响
② 俄乌战争对个股的影响【长城汽车在俄罗斯销量最高】
5、行业因素:
行业在国民经济中地位的变更,发展前景和发展潜力,新兴行业的冲击等都会影响相关股票的价格
白酒行业与茅台收益率对比
6、企业自身因素
企业的经营业绩水平、本身的资产信用、股票红利的设定、外来的发展前景等等都可以影响该企业股票价格变动
个股长期股价随业绩变化的增长和减少
7、市场因素:
主要指市场交易状况、其他金融投资产品的表现、交易因素、供求关系等因素
市场交易影响股票异常波动
8、心理因素:
投资人在受到各个方面的影响产生心理状态改变,往往导致情绪波动,判断失误,这是引起股价狂跌暴涨的重要因素
投资人心理因素是造成股价短期巨大波动的主要因素
十二、基于Numpy股价统计分析实战
1、数据样本
2、股价常用指标
极差:
越高说明波动越明显
股价近期最高价的最大值和最小值的差值
成交量加权平均价格:
英文名VWAP(Volume-Weighted Average Price,成交量加权平均价格)是一个非常重要的经济学量,代表着金融资产的“平均”价格
收益率:
简单收益率,相邻两个价格之间的变化率
对数收益率,指所有价格取对数后两两之间的差值
波动率:
越高说明波动越明显
波动率是对价格变动的一种衡量
年波动率:
对数波动率的标准差除以其均值,再除以交易日倒数的平方根,通常交易日取250天
月波动率:
对数收益率的标准差除以其均值,再乘以交易月的平方根,通常交易月取12月
import numpy as np
from unittest import TestCase
class TestNumpyStock(TestCase):
""" 读取指定列
numpy.loadtxt需要传入4个关键字参数:
1.fname是文件名,数据类型为字符串str;
2.delimiter是分隔符,数据类型为字符串str;
3.usecols是读取的列数,数据类型为元组tuple, 其中元素个数有多少个,则选出多少列;
4.unpack是是否解包,数据类型为布尔bool。
#"""
def testReadFile(self):
file_name = "./demo.csv"
end_price,volumn = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2,6),
unpack=True
)
print("end_price = {}".format(end_price))
print("volumn = {}".format(volumn))
# 计算最大值与最小值
def testMaxAndMin(self):
file_name = "./demo.csv"
high_price,low_price = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(4,5),
unpack=True
)
print("max_price = {}".format(high_price.max()))
print("min_price = {}".format(low_price.min()))
# 计算极差
# 计算股价近期最高价的最大值和最小值的差值 和 计算股价近期最低价的最大值和最小值的差值
def testPtp(self):
file_name = "./demo.csv"
high_price, low_price = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(4, 5),
unpack=True
)
print("max - min of high price : {}".format(np.ptp(high_price)))
print("max - min of low price : {}".format(np.ptp(low_price)))
# 计算成交量加权平均价格
# 成交量加权平均价格,英文名VWAP(Volume-Weighted Average Price,成交量加权平均价格)是一个非常重要的经济学量,代表着金融资产的“平均”价格
def testAVG(self):
file_name = "./demo.csv"
end_price, volumn = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2, 6),
unpack=True
)
print("avg_price = {}".format(np.average(end_price)))
print("VWAP = {}".format(np.average(end_price,weights=volumn)))
# 计算中位数
# 收盘价的中位数
def testMedian(self):
file_name = "./demo.csv"
end_price, volumn = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2, 6),
unpack=True
)
print("median = {}".format(np.median(end_price)))
# 计算方差
# 收盘价的方差
def testVar(self):
file_name = "./demo.csv"
end_price, volumn = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2, 6),
unpack=True
)
print("var = {}".format(np.var(end_price)))
print("var = {}".format(end_price.var()))
# 计算股票收益率、年波动率及月波动率
# 波动率是对价格变动的一种度量,历史波动率可以根据历史价格数据计算得出。计算历史波动率时,需要用到对数收益率
# 年波动率等于对数收益率的标准差除以其均值,再乘以交易日的平方根,通常交易日取250天
# 月波动率等于对数收益率的标准差除以其均值,再乘以交易月的平方根。通常交易月取12月
def testVolatility (self):
file_name = "./demo.csv"
end_price, volumn = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2, 6),
unpack=True
)
log_return = np.diff(np.log(end_price))
annual_volatility = log_return.std() / log_return.mean() * np.sqrt(250)
monthly_volatility = log_return.std() / log_return.mean() * np.sqrt(12)
print("log_return = {}".format(log_return))
print("annual_volatility = {}".format(annual_volatility))
print("monthly_volatility = {}".format(monthly_volatility))
十三、股价均线:
1、 卷积:卷积可用于描述过去作用对当前的影响。卷积是时空响应的叠加,可用于计算"移动平滑"
numpy.convolve(a, v, mode="full"),这是numpy函数中的卷积函数库
参数:
a:(N)输入的一维数组
b:(M)输入的第二个一维数组
mode:{"full","valid","same"}参数可选
“full“默认值,返回一家卷积值,长度是N+M-1,在卷积的边缘处,信号不重叠,存在边际效应
“same”返回的数组长度为max(M,N),边际效应依旧存在
“valid”返回的数组长度为max(M,N)-min(M,N)+1,此时返回的是完全重叠的点。边缘的点无效
2、简单移动均线:
一般用于分析时间序列上的股价趋势
计算股价与等权重的知识函数的卷积
生成权重 -> 卷积运算 -> 均线可视化
3、指数移动均线:
历史数据的权重以指数速度衰减
计算股价与权重衰减的指示函数的卷积
权重初始化 -> 权重衰减 -> 卷积运算 -> 均线可视化
4、代码实现:
import numpy as np
import matplotlib.pyplot as plt
from unittest import TestCase
class TestNumpyMA(TestCase):
def testSMA(self):
file_name = "./demo.csv"
end_price = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2),
unpack=True
)
print(end_price)
N = 5
weights = np.ones(N) / N
print(weights)
sma = np.convolve(weights,end_price)[N-1:-N+1]
print(sma)
plt.plot(sma,linewidth=5)
plt.show()
def testEXP(self):
x = np.arange(5)
y = np.arange(10)
print("x", x) # exp 函数可以计算出每个数组元素的指数
print("y", y)
print("""Exp x : {}""".format(np.exp(x)))
print("""Exp y : {}""".format(np.exp(y)))
print("""Linespace : {}""".format(np.linspace(-1,0,5)))
def testEMA(self):
file_name = "./demo.csv"
end_price = np.loadtxt(
fname=file_name,
delimiter=',',
usecols=(2),
unpack=True
)
print(end_price)
N = 5
weighs = np.exp(np.linspace(-1,0,N))
weighs /= weighs.sum()
print(weighs)
ema = np.convolve(weighs,end_price)[N-1:-N+1]
print(ema)
t = np.arange(N-1,len(end_price))
plt.plot(t,end_price[N-1:],lw=1.0)
plt.plot(t,ema,lw=2.0)
plt.show()
十四、股票时间序列
1、时间序列:
金融领域最重要的数据类型之一
股价、汇率为常见的时间序列数据
2、趋势分析:
主要分析时间序列在某一方向上继续运动
在量化交易领域,我们通过统计手段对投资品的收益率进行时间序列建模,以此来预测未来收益率并产生交易信号
3、序列相关性:
金融时间序列的一个最重要特征是相关性
以投资品的收益率序列为例,我们会经常观察到一段时间内的收益率之间存在正相关或者负相关
4、Pandas时间序列函数
datetime:时间序列最常用的数据类型,方便进行各种时间类型运算
loc:Pandas中对DateFrame进行筛选的函数,相当于SQL中的where
groupby:Pandas中对数据分组函数,相当于SQL中的GroupBy
import matplotlib.pyplot as plt
import pandas as pd
from unittest import TestCase
class TestPandasStock(TestCase):
#读取文件
def testReadFile(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
print(df.info())
print("-------------")
print(df.describe())
#时间处理
def testTime(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df["date"] = pd.to_datetime(df["date"])
df["year"] = df["date"].dt.year
df["month"] = df["date"].dt.month
print(df)
# 最低收盘价
def testCloseMin(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
print("""close min : {}""".format(df["close"].min()))
print("""close min index : {}""".format(df["close"].idxmin()))
print("""close min frame : {}""".format(df.loc[df["close"].idxmin()]))
# 每月平均收盘价与开盘价
def testMean(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df["date"] = pd.to_datetime(df["date"])
df["month"] = df["date"].dt.month
print("""month close mean : {}""".format(df.groupby("month")["close"].mean()))
print("""month open mean : {}""".format(df.groupby("month")["open"].mean()))
# 计算涨跌幅
# 涨跌幅今日收盘价减去昨日收盘价
def testRipples_ratio(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df["date"] = pd.to_datetime(df["date"])
df["rise"] = df["close"].diff()
df["rise_ratio"] = df["rise"] / df.shift(-1)["close"]
print(df)
# 计算股价移动平均
def testMA(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df['ma_5'] = df.close.rolling(window=5).mean()
df['ma_10'] = df.close.rolling(window=10).mean()
df = df.fillna(0)
print(df)
5、K线图
K线图蕴含大量信息,能显示股价的强弱、多空双方力量对比,是技术分析最常用的工具
matplotlib:是一个Python的2D绘图库,它以各种硬拷贝和跨平台的交互式话你就能够生成出版质量级别的图形
mpl_finance:matplotlib finance是python中可以用来画出蜡烛图、线图的分析工具,目前已经从matplotlib中独立出来
import matplotlib.pyplot as plt
import pandas as pd
from mpl_finance import candlestick2_ochl
import mplfinance as mpf
from unittest import TestCase
class TestPandasKline(TestCase):
#读取股票数据,画出K线图
def testKLineChart(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
fig = plt.figure()
axes = fig.add_subplot(111)
candlestick2_ochl(ax=axes,opens=df["open"].values,closes=df["close"].values,highs=df["high"].values,
lows=df["low"].values,width=0.75,colorup='red',colordown='green')
plt.xticks(range(len(df.index.values)),df.index.values,rotation=30)
axes.grid(True)
plt.title("K-Line")
plt.show()
#K线图带交易量
def testKLineByVolume(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df = df[["date","close","open","high","low","volume"]]
df["date"] = pd.to_datetime(df["date"])
df = df.set_index('date')
my_color = mpf.make_marketcolors(
up = 'red',
down = 'green',
wick = 'i',
volume = {'up':'red','down':'green'},
ohlc = 'i'
)
my_style = mpf.make_mpf_style(
marketcolors = my_color,
gridaxis = 'both',
gridstyle = '-.',
rc = {'font.family':'STSong'}
)
mpf.plot(
df,
type = 'candle',
title = 'K-LineByVolume',
ylabel = 'price',
style = my_style,
show_nontrading = False,
volume = True,
ylabel_lower = 'volume',
datetime_format = '%Y-%m-%d',
xrotation = 45,
linecolor = '#00ff00',
tight_layout = False
)
# K线图带交易量及均线
def testKLineByMA(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df = df[["date","close","open","high","low","volume"]]
df["date"] = pd.to_datetime(df["date"])
df = df.set_index('date')
my_color = mpf.make_marketcolors(
up = 'red',
down = 'green',
wick = 'i',
volume = {'up':'red','down':'green'},
ohlc = 'i'
)
my_style = mpf.make_mpf_style(
marketcolors = my_color,
gridaxis = 'both',
gridstyle = '-.',
rc = {'font.family':'STSong'}
)
mpf.plot(
df,
type = 'candle',
mav = [5,10],
title='K-LineByVolume',
ylabel='price',
style=my_style,
show_nontrading=False,
volume=True,
ylabel_lower='volume',
datetime_format='%Y-%m-%d',
xrotation=45,
linecolor='#00ff00',
tight_layout=False
)
6、MACD:
Moving Average Convergence/Divergence,意为异同移动平均线。它刻画的是股价变化的速度
MACD算法:
MACD实现:
① ewm:
Pandas中指数加权移动窗口函数
采用ewm函数+mean() 快捷计算MACD
② bar:
Matplotlib柱状图函数,高效绘制MACD中柱状图
import pandas as pd
import matplotlib.pyplot as plt
from unittest import TestCase
class TestMACD(TestCase):
def cal_macd(self, df, fastperiod=12, slowperiod=26, signalperiod=9):
ewma12= df['close'].ewm(span=fastperiod, adjust=False).mean()
ewmal26 = df['close'].ewm(span=slowperiod, adjust=False).mean()
df['dif'] = ewma12 - ewmal26
df['dea'] = df['dif'].ewm(span=signalperiod, adjust=False).mean()
return df
def cal_macd(self,df,fastperiod=12,slowperiod=26,signalperiod=9):
ewma12 = df['close'].ewm(span=fastperiod,adjust=False).mean()
ewma26 = df['close'].ewm(span=slowperiod,adjust=False).mean()
df['dif'] = ewma12 - ewma26
df['dea'] = df['dif'].ewm(span=signalperiod,adjust=False).mean()
df['bar'] = (df['dif'] - df['dea']) * 2
return df
def test_MACD(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df = df[["date","close","open","high","low","volume"]]
df["date"] = pd.to_datetime(df["date"])
df_macd = self.cal_macd(df)
print(df_macd)
plt.figure()
df_macd['dea'].plot(color="red",label='dea')
df_macd['dif'].plot(color="blue",label='dif')
plt.legend(loc='best')
pos_bar = []
pos_index = []
neg_bar = []
neg_index = []
for index,row in df_macd.iterrows():
if(row['bar'] > 0) :
pos_bar.append(row['bar'])
pos_index.append(index)
else:
neg_bar.append(row['bar'])
neg_index.append(index)
# 大于0用红色表示
plt.bar(pos_index,pos_bar,width=0.5,color='red')
# 小于等于0则用绿色表示
plt.bar(neg_index,neg_bar,width=0.5,color='green')
major_index = df_macd.index[df_macd.index]
major_xtics = df_macd['date'][df_macd.index]
plt.xticks(major_index,major_xtics)
plt.setp(plt.gca().get_xticklabels(),rotation=30)
plt.grid(linestyle='-.')
plt.title('000001平安银行MACD图')
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.show()
7、实现KDJ
中文名叫随机指数。通过价格波动的真实波幅来反映价格走势的强弱和超买超卖现象,在价格尚未上升或下降之前发出买卖信号的一种技术分析指标,适用于短期行情走势分析
rolling:
Pandas中移动窗口函数
每个窗口都是指定的固定大小,快捷计算Ln和Hn
expanding:
Pandas中扩展窗口函数
只设置最小的观测值数量,不固定窗口大小,实现累计计算,即不断扩展,连用expandiing().max()->创新高
import pandas as pd
import matplotlib.pyplot as plt
from unittest import TestCase
class TestKDJ(TestCase):
def cal_kdj(self,df):
low_list = df['low'].rolling(9,min_periods=9).min()
low_list.fillna(value=df['low'].expanding().min(),inplace=True)
high_list = df['high'].rolling(9,min_periods=9).max()
high_list.fillna(value=df['high'].expanding().max(),inplace=True)
rsv = (df['close'] - low_list) / (high_list - low_list) * 100
df['k'] = pd.DataFrame(rsv).ewm(com=2).mean()
df['d'] = df['k'].ewm(com=2).mean()
df['j'] = 3 * df['k'] - 2 * df['d']
return df
def test_KDJ(self):
file_name = "./demo.csv"
df = pd.read_csv(file_name)
df.columns = ["stock_id","date","close","open","high","low","volume"]
df = df[["date","close","open","high","low","volume"]]
df["date"] = pd.to_datetime(df["date"])
df_kdj = self.cal_kdj(df)
print(df_kdj)
plt.figure()
df_kdj['k'].plot(color="red",label='k')
df_kdj['d'].plot(color="yellow",label='d')
df_kdj['j'].plot(color="blue",label='j')
plt.legend(loc='best')
major_index = df_kdj.index[df_kdj.index]
major_xtics = df_kdj['date'][df_kdj.index]
plt.xticks(major_index,major_xtics)
plt.setp(plt.gca().get_xticklabels(),rotation=30)
plt.grid(linestyle='-.')
plt.title('000001平安银行KDJ图')
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.show()
def testBoll(self):
import numpy as np
from matplotlib.pyplot import plot
from matplotlib.pyplot import show
# 绘制布林带
N = 5
weights = np.ones(N) / N
print("Weights", weights)
c = np.loadtxt('demo.csv', delimiter=',', usecols=(2,), unpack=True)
sma = np.convolve(weights, c)[N - 1:-N + 1]
deviation = []
C = len(c)
for i in range(N - 1, C):
if i + N < C:
dev = c[i: i + N]
else:
dev = c[-N:]
averages = np.zeros(N)
averages.fill(sma[i - N - 1])
dev = dev - averages
dev = dev ** 2
dev = np.sqrt(np.mean(dev))
deviation.append(dev)
deviation = 2 * np.array(deviation)
print(len(deviation), len(sma))
upperBB = sma + deviation
lowerBB = sma - deviation
c_slice = c[N - 1:]
between_bands = np.where((c_slice < upperBB) & (c_slice > lowerBB))
print(lowerBB[between_bands])
print(c[between_bands])
print(upperBB[between_bands])
between_bands = len(np.ravel(between_bands))
print("Ratio between bands", float(between_bands) / len(c_slice))
t = np.arange(N - 1, C)
plot(t, c_slice, lw=1.0)
plot(t, sma, lw=2.0)
plot(t, upperBB, lw=3.0)
plot(t, lowerBB, lw=4.0)
show()
十五、策略框架:
1、框架:初始化+策略函数(周期循环)
2、初始化:通过初始化函数设置基准。初始化函数在整个回测或者实盘操作过程中,用于初始化全局变量
函数:initialize(context)
context:Context对象,存放有当前的账户/股票持仓信息
示例:
def initialize(context):
# g为全局变量,设定标的股票为深交所的平安银行
g.security = "000001.XSHE"
3、策略函数:策略开始后,随着时间周期重复执行你的交易策略
示例:
def handle data(context,data):
# 下单一千股
order(g.security, 1000)
# 卖出八百股
order(g.security, -800)
4、实用策略示例:
初始化:
设定投资标的(平安银行)
设定策略运行周期(每日)
策略函数:
如果上一时间点价格高于五天平均价1%,则全仓买入
如果上一时间点价格低于五天平均价,则空仓卖出(画出上一时间点价格)
def initialize(context):
g.security = '000001.XSHE'
run_daily(market_open, time='every_bar')
def market_open(context):
security = g.security
close_data = attribute_history(security,5,'1d',['close'])
MA5 = close_data['close'].mean()
current_price = close_data['close'][-1]
cash = context.portfolio.available_cash
if current_price > 1.01*MA5:
order_value(security, cash)
log.info("买入 %s" % (security))
elif current_price < MA5 and context.portfolio.positions[security].closeable_amount > 0:
order_target(security, 0)
log.info("卖出 %s" % (security))
record(stock_price=current_price)
5、策略设置函数
① 常用策略设置函数
基准:设定业绩比较基准set_benchmark(security)
② 佣金/印花税:
股票类每笔交易时的手续费为:买入时佣金万分之三,卖出时佣金万分之三加上千分之一印花税set_order_cost(cost, type, ref = None)
③ 滑点:
真实的成交价格与下单时预期的价格的偏差
set_slippage(object,type=None,ref=None)
④ 成交量比例:
根据实际行情限制每个订单的成交量
set_option('order_volume_ratio',value)
⑤ 动态复权模式:
设置真实价格,建议开启
set_option('user_real_price',value)
def initialize(context):
# 设置业绩基准为“沪深300”
set_benchmark('000300.XSHG')
g.security = '000001.XSHE'
run_daily(market_open, time='10:00')
# 设置佣金和印花税
set_order_cost(OrderCost(open_commission=0.0003,close_commission=0.0003,close_tax=0.001,min_commission=5),type='stock')
# 滑点设置
set_slippage(PriceRelatedSlippage(0.002),type='stock')
# 成交量设置
set_option('order_volume_ratio',0.5)
# 复权
set_option('use_real_price', False)
def market_open(context):
if g.security not in context.portfolio.positions:
order(g.security,1000)
else:
order(g.security,-800)
6、定时函数介绍:
① 定时函数:设定回测和模拟交易中运行时间和频率
② 月度:run_monthly(func,monthday,time='open',reference_secuity)
③ 周度:run_weekly(func,weekday,time='open',reference_secuity)
④ 日度:run_daily(func,time='open',reference_secuity)
def initialize(context):
# 设置业绩基准为“沪深300”
set_benchmark('000300.XSHG')
g.security = '000001.XSHE'
# # 设置佣金和印花税
# set_order_cost(OrderCost(open_commission=0.0003,close_commission=0.0003,close_tax=0.001,min_commission=5),type='stock')
# # 滑点设置
# set_slippage(PriceRelatedSlippage(0.002),type='stock')
# # 成交量设置
# set_option('order_volume_ratio',0.5)
# # 复权
# set_option('use_real_price', False)
# # 每分钟
# run_daily(market_open, time='every_bar',reference_security='000300.XSHG')
# 每月第一个交易日
# run_monthly(market_open, 1, time='open')
# 每周最后一个交易日
run_weekly(market_open,-1,time='open')
def market_open(context):
if g.security not in context.portfolio.positions:
order(g.security,1000)
else:
order(g.security,-800)
7、交易函数
① 交易数量:
order(security,amount,style=None,side='long',pindex=0)
securiy:股票代码
amount:交易数量(负数表示卖出)
style:下单类型
side:short空(一般不允许)/long多
pindex:仓位号,默认为0
例如:按限单价30买入100股
order('600000.XSHG',100,LimitOrderStyle(30.0))
② 股票价值:
order_value(security, value, style=None, side='long',pindex=0)
security:股票代码
value:股票价值(负数代表卖出)
style:下单类型
side:short空(一般不允许)/long多
pindex:仓位号,默认为0
例如:按卖出价值为5000元的股票
order_value('600000.XSHG',-5000)
③ 目标数量
order_target(security,amount,style=None,side='long',pindex=0,close_today=False)
security:股票代码
amount:交易数量(负数表示卖出)
style:下单类型
side:short空(一般不允许)/long多
pindex:仓位号,默认为0
例如:买入平安银行所有股票到100股
order_target('000001.XSHE',100)
④ 成交订单:
get_orders(order_id=None,security=None,status=None)
例如:
get_orders(order_id='123')订单id查询订单号为“123”的订单
get_orders(security=‘000001.XSHE’)查询所有标的为000001.XSHE的订单
⑤ 未完成订单:
get_open_orders()
在每天交易结束之后获取当天所有的未完成订单
def after_market_close(context):
orders=get_open_orders()
for_order in orders:
log.info(_order.order_id)
⑥ 撤单函数:
cancel_order(order)
在每天交易结束之后对未完成订单进行撤单
def after_market_close(context):
orders=get_open_orders()
for_order in orders.values():
cancel_order(_order)
⑦ 账户出入金:
inout_cash(cash,pindex=0)
cash:浮点数,负数表示出金
pindex:仓位号,默认为0
例如:向账户增加10000元
inout_cash(10000,pindex=0)
def initialize(context):
# 设置业绩基准为“沪深300”
set_benchmark('000300.XSHG')
g.security = '000001.XSHE'
run_daily(market_open, time='9:30')
run_daily(after_market_close, '15:30')
def market_open(context):
# 向账户增加10000元
inout_cash(10000, pindex=0)
# 查询可用资金
log.info("""账户可用资金:{}""".format(context.portfolio.subportfolios[0].available_cash))
# 如果没有持仓
if g.security not in context.portfolio.positions:
# #全仓买入
# order_value(g.security,cash)
# 下单1000股
order(g.security,1000)
else:
#全仓卖出
# order_target(g.security,0)
# 卖出500股
order(g.security,-100)
def after_market_close(context):
# 获取当天所有未完成订单
orders = get_open_orders()
for _order in orders:
log.info("""未完成订单: {}""".format(_order))
for _order in orders:
#对未完成订单进行撤单
cancel_order(_order)
log.info("""撤单: {}""".format(_order))
8、交易对象:
① Order对象:
订单处理流程:
订单创建 -> 订单检查 -> 报单 -> 确认委托 -> 撮合
commission:交易费用(佣金、税费等)
is_buy:bool值,买还是卖
status:状态,一个OrderStatus值
price:平均成交价格,已经成交的股票的平均成交价格
def initialize(context):
# 设置业绩基准为“沪深300”
set_benchmark('000300.XSHG')
g.security = '000001.XSHE'
run_weekly(market_open,1,time='open')
def market_open(context):
# 如果没有持仓
if g.security not in context.portfolio.positions:
orders = order(g.security,100)
print(orders)
if orders is None:
print("创建订单失败...")
else:
print("""交易费用:{}""",format(orders.commission))
print("""是否买单:{}""",format(orders.is_buy))
print("""订单状态:{}""",format(orders.status))
print("""订单平均成交价格:{}""",format(orders.price))
else:
order(g.security, -800)
② Trader对象:
订单成交相关信息:
time:交易时间,[datetime.datetime]对象
security:标的代码
amount:交易数量
price:交易价格
trade_id:交易记录id
order_id:对应的订单id
def initialize(context):
# 设置业绩基准为“沪深300”
set_benchmark('000300.XSHG')
g.security = '000001.XSHE'
run_daily(market_open,time='9:30')
run_daily(after_market_close, time='15:30')
def market_open(context):
# 如果没有持仓
if g.security not in context.portfolio.positions:
# 下单1000股
order(g.security,1000)
else:
# 卖出800股
order(g.security,-800)
def after_market_close(context):
print("""闭市后""")
# 得到所有的额成交记录
trades = get_trades()
for _trade in trades.values():
print("""成交记录:{}""".format(_trade))
print("""成交时间:{}""".format(_trade.time))
print("""对应的订单id:{}""".format(_trade.order_id))
print("一天结束")
9、策略信息
① Context对象:
策略信息总览,包含账户、时间等信息
subportfolios:当前单个操作仓位的资金、标的信息,是一个SubPortfolio的数组
portfolio:账户信息,即subportfolios的汇总信息,Portfolio对象,单个操作仓位时,portfolio指向subportfolios[0]
current_dt:当前单位时间的开始时间,[datetime.datetime]对象
previous_date:前一个交易日,[datetime.date]对象,注意,这是一个日期,是date,而不是datetime
universe:查询set_universe()设定的股票池,比如:['000001.XSHE','600000.XSHG']
def initialize(context):
set_benchmark('000001.XSHE')
def handle_data(context,data):
# context.portfolio变为整数1
context.portfolio = 1
log.info(context.portfolio)
# 恢复系统变量
del context.portfolio
# context.portfolio将变成用户账户信息
log.info(context.portfolio.total_value)
# 输出账户总资产
log.info(context.portfolio.total_value)
# 输出持仓金额
log.info(context.portfolio.positions_value)
# 输出今日日期
log.info(context.current_dt.day)
# 输出总权益的累计收益
log.info(context.portfolio.returns)
#获取仓位subportfolios[0]的可用资金
log.info(context.subportfolios[0].available_cash)
② Position对象:
输出持有标的的信息
security:标的代码
price:最新行情价格
total_amount:总仓位,不包括挂单冻结仓位
init_time:建仓时间,格式为datetime.datetime
def initialize(context):
g.security = "000001.XSHE"
def handle_data(context,data):
# 如果没有持仓
if g.security not in context.portfolio.positions:
# 下单1000股
order(g.security,1000)
else:
# 卖出800股
order(g.security,-800)
print(type(context.portfolio.long_positions))
long_positions_dict = context.portfolio.long_positions
for position in list(long_positions_dict.values()):
print("""标的:{},总仓位:{},标的价值:{},建仓时间:{}"""
.format(position.security,position.total_amount,
position.value,position.init_time))
10、账户信息:
① Portfolio对象:总账户信息
long_positions:多单的仓位,一个dict,key是证券代码,value是[Position]对象
short_positions:空单的仓位,一个dict,key是证券代码,value是[Position]对象
total_value:总的权益,包括现金,保证金(期货 )或者仓位(股票)的总价值,可用来计算收益
returns:总权益的累计收益;(当前总资产+今日出入金-昨日总资产)/ 昨日总资产
starting_cash:初始资金,现在等于inout_cash
positions_value:持仓价值
def initialize(context):
g.security = "000001.XSHE"
def handle_data(context,data):
# 如果没有持仓
if g.security not in context.portfolio.positions:
order(g.security,1000)
else:
order(g.security,-800)
print("""多单的仓位:{}""",format(context.portfolio.long_positions))
print("""空单的仓位:{}""",format(context.portfolio.short_positions))
print("""总权益:{}""",format(context.portfolio.total_value))
print("""总权益的累计收益:{}""".format(context.portfolio.returns))
print("""初始资金:{}""".format(context.portfolio.starting_cash))
print("""持仓价值:{}""".format(context.portfolio.positions_value))
② SubPortfolio对象:子账户信息
inout_cash:累计出入金,如初始资金1000,后来转移出去100,则这个值是1000-100
avilable_cash:可用资金,可用来购买证券的资金
transferable_cash:可取资金,即可体现的资金,不包括今日卖出证券所得资金
locked_cash:挂单锁住资金
type:账户所属类型
def initialize(context):
g.security = "000001.XSHE"
def handle_data(context,data):
# 如果没有持仓
if g.security not in context.portfolio.positions:
order(g.security,1000)
else:
order(g.security,-800)
print("""累计出入金:{}""",format(context.subportfolios[0].inout_cash))
print("""可用资金:{}""".format(context.subportfolios[0].available_cash))
print("""可取资金:""".format(context.subportfolios[0].transferable_cash))
print("""挂单锁住资金:{}""".format(context.subportfolios[0].locked_cash))
print("""账户所属类型:{}""".format(context.subportfolios[0].type))
11、股票历史
① history()函数
# 6-1 history() 函数 代码实现1
from jqdata import *
security_list = ['600000.XSHG', '600006.XSHG']
data = history(count=10, unit='10d',field='open', security_list=security_list,df=True)
print(data)
# 6-1 history() 函数 代码实现2
from jqdata import *
security_list = ['600000.XSHG', '600006.XSHG']
data = history(count=3, field='money', security_list=security_list, df=False)
print(data)
② attribute_history()函数
# 6-1 attribute_history()函数 代码实现1
from jqdata import *
security = '600000.XSHG'
data = attribute_history(security=security,count=3, fields=['open','money','high'])
print(data)
# 6-1 attribute_history()函数 代码实现2
print("最近5个交易日最高价的平均价是:")
security = '600000.XSHG'
high_5d = attribute_history(security=security, count=5, fields=['high'])
avg_5d = high_5d.mean()
print(avg_5d)
12、获取财务数据
# 6-2 get_fundamentals()函数 代码实现1
# 查询平安银行2022年9月1日的总市值
q = query(
valuation
).filter(
valuation.code == '000001.XSHE'
)
df = get_fundamentals(q, '2022-09-01')
# 打印出总市值
print(df['market_cap'][0])
# 6-2 get_fundamentals()函数 代码实现2
# 查询平安银行2022年第二季度的财务数据
q = query(
income.statDate,
income.code,
income.basic_eps,
balance.cash_equivalents
).filter(
income.code == '000001.XSHE',
)
rets = get_fundamentals(q, statDate='2022q2')
print(rets)
# 6-3 get_fundamentals_continuously()函数
q = query(valuation.turnover_ratio,
valuation.market_cap,
indicator.eps
).filter(valuation.code.in_(['000001.XSHE', '600000.XSHG']))
result = get_fundamentals_continuously(q, end_date='2022-01-01', count=5,panel=False)
print(result)
13、成分股:
指数成分股函数:
查询制定指数指定日期可交易的成分股列表
get_index_stocks(index_symbol,date=None)
index_symbol:指数代码
date/statdate:获得一个字符串(格式类似‘2015-10-15’)或者datetime对象
返回:返回股票代码的list
# 返回沪深300的股票(输出100个)
stocks = get_index_stocks('000300.XSHG')
print(stocks[0:100])
行业成分股函数:
查询指定行业的所有股票
get_industy_stocks(iindustry_code,date=None)
industry_code:行业编码
date/statdate:获得一个字符串(格式类似‘2015-10-15’)或者datetime对象
返回:返回股票代码的list
# 获取计算机/互联网行业的成分股
stocks = get_industry_stocks('I64')
print(stocks)
概念成分股函数:
查询制定概念板块的所有股票
get_concept_stocks(concept_code,date=None)
concept_code:行业编码
date/statdate:获取一个字符串(格式类似‘2015-10-15’)或者datetime对象
返回:返回股票代码的list
# 获取风电概念板块的成分股
stocks = get_concept_stocks('sc0084',date='2022-06-01')
print(stocks)
14、标的信息:
① 获取所有标的信息:
获取平台支持的所有股票、基金、指数、期货、期权信息
get_all_securities(types=[],date=None)
types:security种类,list类型。支持:’stock‘,'fund','index','futures'等
date:获取一个字符串(格式类似’2015-10-15‘)或者datetime对象
返回:返回dataframe对象
# 查询所有的标的信息,返回前十
print(get_all_securities()[:10])
# 查询平台所有ETF信息
print(get_all_securities(types=['etf'],date='2022-09-01')[:10])
② 获取单个标的信息:
获取单个标的信息,包括中文名称,简称,上市日期,退市日期,标的种类等等
get_security_info(code,date=None)
code:证券代码
date:获取一个字符串(格式类似’2015-10-15‘)或者datetime对象
返回:返回数据对象
#获取000001的标的信息
start_date = get_security_info('000001.XSHE').start_date
print(start_date)
type = get_security_info('000001.XSHE').type
print(type)
print(get_security_info('000001.XSHE'))
15、交易数据
① 获取行情数据:
获取证券行情数据,可查询多个标的多个数据字段
get_price(security,start_date=None,end_date=None.frequancy='daily',
fields=None,skip_paused=False,fq='pre',count=None,panel=True,fill_paused=True)
security:一支股票代码或者一个股票代码的list
count:与start_date二选一,不可同时使用。数量,返回的结果集的行数,即表示获取end_date之前几个frequency的数据
start_date:与count二选一,不可同时使用。字符串或者datetime对象,开始时间
end_date:同start_date,结束时间
frequence:单位时间长度,几天或者几分钟,,现在支持’Xd‘,'Xm','daily'(等同于’1d‘),’minute‘(等同于’1m‘),X是一个正整数,分别表示X天和X分钟
fields:字符串list,选择要获取的行情数据字段,默认是None(常用['open','close','high','low','volumn','money']这几个标准字段)
skip_paused:是否跳过不交易日期(包括停牌,未上市或者退市后的日期)
fq:复权选项(对股票/基金的加个字段、成交量字段及factor字段生效)
panel:获取夺标的数据时建议设置panel为False,在pandas 0.25版后,panel被彻底移除
fill_paused:对于停牌股票的价格处理,默认为True;True表示用pre_close价格填充;False表示使用Nan填充停牌的数据
# 获取一只股票
df = get_price('000001.XSHE',start_date='2015-03-01 14:00:00',end_date='2015-03-02 23:00:00',frequency='1m')
print(df)
# 获取多只股票
# 获取中证100所有成分股的股票数据
df = get_price(get_index_stocks('399905.XSHE'),panel=False)
# print(df)
# 只看指定数据的数据
print(df.loc[df['code']=='000009.XSHE'])
② 获取龙虎榜数据:
get_billboard_list(stock_list,start_date,end_date,count)
stock_list:包含股票代码的list,当值为None时,返回指定日期的所有股票
start_date:开始日期
end_date:结束日期
count:交易日数量,可以与end_date同时使用,表示获取end_date前count个交易日的数据(含end_date当日)
# 获取龙虎榜数据
# 获取2022-09-01的龙虎榜数据
df = get_billboard_list(stock_list=None,end_date='2022-09-01',count=2)
print(df[['code','sales_depart_name','rank']][:10])
十六、量化选股:
1、量化选股概况:
量化选股: 利用数量化的方法选择股票组合,期望该股票组合能够获得超越基准收益率的投资行为
技术面选股:利用各种技术理论或技术指标来分析和预测股票未来价格趋势
基本面选股:通过对一家上市公司在发展过程中面临的外部因素和自身因素进行分析,对其未来的发展前景进行预测,判断该上市公司的股票是否值得买进
2、量化选股注意事项:
① 分配多股,减少单股重仓的情况
② 全面研究个股基本面,增强个股判断逻辑和支撑
③ 主动投资而非被动投资
④ 只是提高胜率的工具之一
选白马股
# 7-1(选白马股)
import datetime
## 初始化函数,设定要操作的股票、基准等等
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# True为开启动态复权模式,使用真实价格交易
set_option('use_real_price', True)
# 设定成交量比例
set_option('order_volume_ratio', 1)
# 股票类交易手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, \
open_commission=0.0003, close_commission=0.0003,\
close_today_commission=0, min_commission=5), type='stock')
# 持仓数量
g.stocknum = 20
# 交易日计时器
g.days = 0
# 调仓频率
g.refresh_rate = 100
# 运行函数
run_daily(trade, 'every_bar')
## 选出逻辑
def check_stocks(context):
# 设定查询条件
q = query(
indicator.code,
valuation.capitalization,
indicator.roe,
indicator.gross_profit_margin,
).filter(
valuation.market_cap > 50,#1.总市值>50亿
valuation.circulating_market_cap > valuation.market_cap*0.95,#3.流通盘比例>95%
indicator.gross_profit_margin > 20,#4.销售毛利率>20%
indicator.roe > 20,#5.扣非净资产收益率>20%
).order_by(
valuation.market_cap.desc()
).limit(
100
)
df = get_fundamentals(q, statDate=str(context.current_dt)[:4])
buylist = list(df['code'])
#上市天数>750(抛开3年以内的次新)
buylist = delect_stock(buylist, context.current_dt, 750)
buylist = filter_paused_stock(buylist)[:20]
return buylist
## 交易函数
def trade(context):
if g.days%g.refresh_rate == 0:
## 选股
stock_list = check_stocks(context)
## 获取持仓列表
sell_list = list(context.portfolio.positions.keys())
sells = list( set(sell_list).difference(set(stock_list)) )
#先卖再买
for stock in sells:
order_target_value(stock, 0)
## 分配资金
if len(context.portfolio.positions) < g.stocknum :
num = g.stocknum - len(context.portfolio.positions)
cash = context.portfolio.cash/num
else:
cash = 0
for stock in stock_list:
if len(context.portfolio.positions) < g.stocknum \
and stock not in context.portfolio.positions:
order_value(stock, cash)
# 天计数加一
g.days = 1
else:
g.days += 1
# 过滤停牌股票
def filter_paused_stock(stock_list):
current_data = get_current_data()
return [stock for stock in stock_list if not current_data[stock].paused]
#排除次新
def delect_stock(stocks,beginDate,n=180):
#去除上市距beginDate不足6个月的股票
stockList = []
for stock in stocks:
start_date = get_security_info(stock).start_date
if start_date < (beginDate-timedelta(days = n)).date():
stockList.append(stock)
return stockList
2、营收因子选股
① 财务因子介绍:
评价企业的基本面情况,通常包括成长类因子,规格类因子,价值类因子以及质量类因子
② 成长类因子:
在财务因子选股中,常用的方法是选用成长类因子进行选股。成长类因子包括营收因子与利润因子
③ 规模类因子:
规模类因子反映公司规模情况,主要用于体现市值大营业总输入小对投资收益的影响。规模类因子包括总市值,流通市值,总股本,流通股本
④ 价值类因子:
价值投资是一个久经考验的投资策略,惯例是购买那种相对低价的股票,转换成在基本面标准度量股息、账面价值、利润、现金流或者其他公司价值的方法。价值类因子包括市净率,市销率,以及市盈率
⑤ 质量类因子:
质量类因子指与股票的财务质量、资本结构相关的因子。质量类因子包括净资产收益率,以及总资产净利率
⑥ 营收因子:
营收因子包括营业收入同比增长率、营业收入环比增长率、营业总收入
⑦ 利润因子:
利润因子包括净利润同比增长率、净利润环比增长率、营业利润率、销售净利润、销售毛利率
⑧ 营业收入同比增长率:
(当期营业收入-上期营业收入)/ 上期营业收入*100%
上期营业收入一般指上一年度/季度/月度同期营业收入,此处指上一年度的同期营业收入
get_fundamemtals(
query(
indicator.inc_revenue_year_on_year
).filter({查询条件})
,date={查询日期}
)
⑨ 营业收入环比增长率:
(本期营业收入的值-上一期营业收入的值)/上一期营业收入的值*100%
环比增长率是针对上一期的,而同比增长率是相对与上一年度同一期的
get_fundamentals(
query(
indicator.inc_revenue_year_on_year
).filter({查询条件})
,date={查询日期}
)
⑩ 营业是总收入
主营业务收入+其他业务收入
net_profit_to_total_revenue
get_fundamentals(
query(
indicator.net_profit_to_total_revenue
).filter({查询条件})
,date={查询日期}
)
2、财务因子选股
净利润同比增长率:
净利润指企业的税后利润
(当期净利润-上期净利润)/ 上期净利润绝对值*100%
上期净利润指的上一年度的同期净利润
get_fundamentals(
query(
indicator.inc_net_profit_year_on_year
).filter({查询条件})
,date={查询日期}
)
净利润环比增长率:
(本期净利润-上一期净利润)/上一期净利润*100%
环比增长率是针对上一期的,而同比增长率是相对上一年度同一期的
get_fundamentals(
query(
indicator.inc_net_profit_annual
).filter({查询条件})
,date={查询日期}
)
营业利润率
指经营所得的营业利润占销售净额的百分比,或占投入资本额的百分比
营业利润/全部业务收入*100%
get_fundamentals(
query(
indicator.operation_profit_to_total_revenue
).filter({查询条件})
,date={查询日期}
)
销售净利率:
指企业实现净利润与销售收入的对比关系,用以衡量企业在一定时期的销售收入获取的能力
净利润/销售收入*100
get_fundamentals(
query(
indicator.net_profit_margin
).filter({查询条件})
,date={查询日期}
)
销售毛利润:
毛利是销售净收入与产品成本的差
销售毛利率是毛利占销售净值的百分比
(销售净收入-产品成本)/销售净收入
get_fundamentals(
query(
indicator.gross_profit_margin
).filter({查询条件})
,date={查询日期}
)
3、规模类因子
① 规模类因子介绍
规模类因子反映公司规模情况,主要用于体现市值大小对投资收益的影响
指标:规模类因子包括总市值、流通市值、总股本、流通股本
② 总市值
在某特定时间内股票总价值
总股本数*股价
总市值用来表示个股权重大小或大盘的规模大小
get_fundamentals(
query(
valuation.market_cap
).filter({查询条件})
,date={查询日期}
)
③ 流通市值
在某特定时间内当时可交易流通股票总价值
可交易的流通股股数*股价
流通市值占总市值的比重(流通盘比例)越大,说明股票的时长价格越能反应出公司的真实价值
③ 流通市值
在某特定时间内当时可交易流通股票总价值
可交易的流通股股数*股价
流通市值占总市值的比重(流通盘比例)越大,说明股票的时长价格越能反应出公司的真实价值
get_fundamentals(
query(
valuation.circulating_market_cap
).filter({查询条件})
,date={查询日期}
)
④ 总股本:
指公司已发行的普通股股份总数(包含A股、B股和H股的总股本),单位万股
get_fundamentals(
query(
valuation.capitalization
).filter({查询条件})
,date={查询日期}
)
⑤ 流通股本
指公司已发行的境内上市流通、以人民币兑换的股份数,即A股市场的流通股本,单位万股
get_fundamentals(
query(
valuation.circulating_cap
).filter({查询条件})
,date={查询日期}
)
4、价值类因子
一、价值类因子
① 价值类因子介绍
即价值投资,是一种久经考验的投资策略。通过购买那种相对低位的股票,转换成在基本面准备度量股息、账面价值、利润、现金流或其他公司价值的方法
指标:价值类因子包括市净率、市销率、(动态/静态)市盈率
② 市净率
每股市价/每股净资产
市净率可用于股票投资分析,一般来说市净率较低的股票,投资价值较高,相反,则投资价值较低。在判断投资价值时还要考虑当时的市场环境以及公司经营情况、赢利能力等因素
get_fundamentals(
query(
Valuation.pb_ratio
).filter({查询条件})
,date={查询日期}
)
③ 市销率
股价/每股销售额
在国内证券市场,运用这一指标来选股可以提出哪些市盈率很低但主营业务没有核心竞争力而主要是依靠非经营性损益而增加利润的股票(上市公司)。该项指标既有助于考察公司收益基础的稳定性和可靠性,又能有效把握其收益的质量水平
get_fundamentals(
query(
Valuation.ps_ratio
).filter({查询条件})
,date={查询日期}
)
④(动态/静态)市盈率
动态市盈率:动态市盈率是指还没有真正实现的下一年度的预测利润的市盈率
静态市盈率:静态市盈率(即广泛意义上的市盈率)表示该公司需要积累多少年的盈利才能达到如今的市价水平
动态市盈率=股票现价/未来每股收益的预测值
静态市盈率=股票现价/每股收益
市盈率指标数值越小说明投资回收期越短,风险越小
get_fundamentals(
query(
Valuation.pcf_ratio,
Valuation.pe_ratio
).filter({查询条件})
,date={查询日期}
)
5、质量类因子:
① 质量类因子介绍:
质量类因子指与股票的财务质量、资本结构相关的因子。影响质量因子的因素大致包括:公司的盈利能力、盈利稳定性、资本结构、成长性、会计质量、派息/摊薄、投资能力等
指标:质量类因子包括净资产收益率、总资产净利率
② 净资产收益率:
税后利润/所有者权益*100%
净资产收益率时企业税后利润除以净资产得到的百分比率,该指标反映股东权益的收益水平,用以衡量企业运用自由资本的效率。指标越高,说明投资带来的收益越高
get_fundamentals(
query(
Indicator.roe
).filter({查询条件})
,date={查询日期}
)
③ 总资产净利率:
净利润/平均资产总额*100%
总资产净利润反映的是公司运用全部资产获得利润的水平,即公司每占用1元的资产平均能获得多少元的利润。总资产净利率越高,表明公司投入产出水平越高,资产运营越有效,成本费用的控制水平越高
get_fundamentals(
query(
Indicator.roa
).filter({查询条件})
,date={查询日期}
)
十七、量化择时:
1、量化择时基本概念
量化择时就是利用数量化的方法,通过对各种宏观微观指标的量化分析,试图找到影响大盘走势的关键信息,并且对未来走势进行预测。通俗来说,就是采用量化的方式判断买点和卖点
2、量化择时常用方法:
趋势量化择时、市场情绪量化择时
3、趋势择时:
基本思想来自于技术分析,技术分析认为趋势存在延续性,因此只要找到趋势方向,跟随操作即可。趋势择时的主要指标有MA、MACD、DMA等
4、市场情绪量化择时:
利用投资者的热情来判断大势方向,当情绪热烈时,大盘可能会继续涨;当投资者七年光绪低迷,大盘可能继续下跌。常用方法:调查问卷、开户人数、搜索指数、报告评级、融资融券数据、舆情数据等
5、技术指标理论:
三个假设:技术指标的理论基础基于三项市场假设--市场行为涵盖一切信息;价格沿趋势移动;历史会重演
技术指标:技术指标是技术分析中使用最多的一种方法,通过考虑市场行为的多个方面建立一个数学模型,并给出完整的数学计算公式,从而得到一个体现证券市场的某个方面内在实质的数字,即所谓的技术指标值
技术指标分类:
① 趋向指标:技术趋向指标是识别和追踪有趋势的图形类指标,其特点是不试图捕顶和测底,如均线指标、MACD指标等
② 反趋向指标:反趋向指标又称为振荡指标,是识别和追踪趋势运行的转折点的图形类指标,其特点是具有强烈的捕顶和捉底的意图,对市场转折点敏感,如随机指标KDJ、强弱指标RSI等
③ 压力支撑指标:压力支撑指标,又称通道指标,是通过顶部轨道线和底部轨道线,试图捕捉行情的顶部和底部的图形类指标,其特点是具有明显的压力线,也有明显的支撑线,如布林带、BOLL指标、XS薛斯通道指标
④ 量价指标:量价指标就是通过成交量变动来分析捕捉价格未来走势的图形类指标,其特点是分析成交量与价格涨跌的关系,如OBV能量潮指标、VOL成交量指标等
6、量化择时
趋向指标:
趋向指标介绍:
定义:趋向指标(DMI)又称动向指标。其基本原理是通过分析股价在上升及下跌过程中的均衡,即供需关系受价格的变动由均衡到失衡的循环过程,从而提供对趋势判断的依据
原理:在大多数指标中都是以每一日的收盘价走势及升幅、跌幅的累计数来计算出不同的分析数据,其不足之处在于忽略了每一日的高价低价的波动幅度。而DMI指标则是把每日的高低波动的幅度因素计算在内,来分析预测未来的走势
MACD:
定义:即平滑异同移动平均线,主要表示经过平滑处理后均线的差异程度。一般用来研判股票价格变化的方向、强度和趋势
快线DIFF上穿慢线DEA,红柱出现的第一天,称为金叉,是买进持有的时机
快线DIFF下穿慢线DEA,绿柱出现的第一天,称为死叉,是卖出空仓的时机
实现方式:
From jqlib.technical_analysis import *
MACD(security_list,check_date,SHORT,LONG,MID)
security_list:股票列表
check_date:要查询数据的日期
SHORT:快线【短周期均线】
LONG:慢线【长周期均线】
MID:计算signalperiod天的macd的EMA均线
示例:
MACD(security_list=’000001.XSHE’,check_date=’2022-09-01’,SHORT=12,LONG=26,MID=9)
返回:
DIF,DEA和MACD的值
字典(dict):键(key)为股票代码,值(value)为数据
EMV:
即简易波动指标。股票中间价的相对波动幅度是以相对成交除以相对振幅作为衡量股票中间价波动百分比的基数。EMV值增加代表成交量增加,这是价格上升阶段的正常信号。EMV下跌代表了缩量下跌,这是价格上升阶段的正常信号。
B=(前日最高+前日最低)/2
C=今日最高-今日最低
当EMV从底部到顶部穿过0轴时,买入
当EMV从上到下穿过0轴时,卖出
From jqlib.technical_analysis import *
EMV(security_list, check_date, N, M, unit=’1d’,
Include_now=True, fq_ref_date=None)
Security_list:股票列表
Check_date:要查询数据的日期
N:N日内EM累加和
M:MAEMV(即EMV的M日简单移动平均)
常见的参数N为14,参数M为9
Unit:统计周期,默认为‘1d’
Include_now:是否包含当前周期,默认为True
Fq_ref_date:复权基准日,默认为None
示例:
EMV(security_list,check_date=’2022-09-01’,N=14,M=9,unit=’1d’,include_now=True,
Fq_ref_date=None)
返回:
EMV和MAEMV的值
字典(dict):键(key)为股票代码,值(value)为数据
UOS:
即终极波动指标。UOS指标是一种多方位功能的指标,除了趋势确认及超买超卖方面的作用之外,它的“突破”讯号不仅可以提供最适当的交易时机之外,更可以进一步加强指标的可靠度
ACC2=(收盘价-TL的N2日累和)/(TH-TL的N2日类和)
ACC3=(收盘价-TL的N3日累和)/(TH-TL的N3日类和)
UOS短线抄底:UOS上穿50
UOS短线卖顶:UOS下穿65
UOS中长期抄底:UOS上传35
UOS中长期卖顶:UOS下穿70
from jqlib.technical_analysis import *
UOS(security_list, check_date, N1 = 7,N2 = 6, unit='1d', include_now = True, fq_ref_date=None)
security_list:股票列表
check_date:要查询数据的日期
一、就业方向:
1、投资银行:高盛、华泰联合证券
2、证券公司:中信证券、国泰君安证券
3、私募基金:幻方量化、UBI
4、会计事务所:普华永道、Deloitte
5、软件公司:蚂蚁集团、万得
二、就业要求:
1、证券机构:金融投研及金融工程团队、一般要求硕士以上
2、私募公司:注重个人能力,学历要求并不高
3、金融科技:通用策略模型开发、量化交易系统及平台开发
三、行业收入:
1、总体收入较高,受金融行业整体薪资影响,目前金融行业整体薪资呈下降趋势,薪资较多集中在15-30K左右
四、工作岗位
1、量化开发工程师:开发和测试量化交易系统软件,实现策略代码实盘运行
五、工作内容
1、量化数据采集、清洗及挖掘
2、实时及历史策略回测系统开发
3、量化因子库开发及量化策略实现
4、量化大数据存储分析平台的设计与实现
5、行情数据服务的设计及实现
6、衍生数据服务的设计与实现
六、必备技能
1、熟悉Python中的至少一种,熟悉TCP/IP网络编程。具有 一定的软件架构能力
2、能够独立完成数据获取、数据采集、数据清洗、数据验证、挖掘特征等
3、熟练掌握金融分析理论、模型与计算工具,有了量化交易模型实操经验是加分项
4、在数学、概率统计、性能优化、算法等方面具有扎实的理论基础及实操经验
5、过硬的学历背景是高加分项
七、案例分享经验总结:
1、扎实的计算机理论基础与实践经验,需要coding能力,不需要有过多的金融专业知识,可在工作中边练边学,根据应聘的岗位内容提前准备
2、年龄不是太大问题,项目经验最为重要,平时积累人脉非常重要
3、可适当在中小型量化企业锻炼2年,积累能力,真正热爱量化交易,自学能力要求高
八、是否要转行量化开发
1、兴趣是最好的老师
2、独立coding,debug是量化交易的基础
3、需要很强的自学能力
4、能独立开发量化交易策略,具有一定实盘经验是非常大的加分项
八、逻辑推理面试题:
(一)烧绳子【分治思想】
1、质量不均的绳子烧尽需要1h,提供若干个绳子,请问如何计算出75min?
解法:
把第一根绳子点燃,完全燃烧用时1小时
取第二根绳子,两头对折一起点,完全燃烧用15分钟
两个时间相加则为75分钟
(二)小球称重【贪心算法,最佳情况】
1、假设你有12个外观相同的球,其中一个球和其他球的重量不一致,如果给你一个天平,最少称几次你可以找出这只球
解法:三叉树
(三)三门问题【第一次选还是第二次选的问题】
1、参赛者会看见三扇关闭了的门,选中后面有汽车的那扇门就可以赢得该汽车或奖品,而另外两扇门后面则各藏有一只山羊。你选择一扇们但不打开,这是主持人会在另两扇门中打开一个后面是山羊的门,换不换自己刚才选择的门
换,获胜概率2/3
不换,获胜概率1/3
八、概率统计类面试题:
(一)见面问题
1、两个人相约在8点到9点时间段见面,彼此等15分钟,见不到人就走。两人在8点至9点任一时刻到达目的地,求两人能见面的概率?
解法:
几何概型,总体概率空间为正方形[0,60,0,60]
|x-y| <= 15
两人见面的概率 = 1 - 45*45 / 60 * 60
= 7/16
(二)飞机上找座位
1、有100位乘客在排队登上飞机。飞机上恰好有100个座位。每位乘客都有票,每张票对应有一个特定座位。
乘客们依次登机,A首先登上飞机,他看不懂座位号,也不知道哪个座位号是他的,所以随机选了一个座位,假装这就是他应该做的座位。
其余乘客登机依次,如果他们发现自己的座位是空的,他们会就座。如果他们发现自己的座位已经友人了,他们会随机另外选择一个座位,直到每个人都登上了飞机并就座。
那么,最后一个登上飞机的人坐在自己本来应该做的位置上的概率是多少?
解法:
考虑只有A和你的情况,你最后坐上自己座位的概率是50%
考虑只有A、B和你的情况,你最后坐上自己座位的概率是
P=1/3 + 1/3 * 1/2 =50%
归纳法推理,最后一名乘客坐上自己座位的概率是50%
(三)扔硬币
1、假设我不断地扔硬币,每次扔到正面记一分,扔到反面扣一分,那么,我得到三分时,期望要扔硬多少次
思路:
设我在得0分是,扔出3分的期望次数为X0,同理可记我在得i分时,扔出3分的期望次数为Xi
得1分时,我们消耗一次机会,有1/2的概率退化为0分,有1/2的概率进化为2分,则
X1=1 + 0.5X0 + 0.5X2
易得
X0 = 1 + X1,
X2= 1 + 0.5X1 + 0.5X3,
X3=0
解四元一次方程得,X0=9,X1=8,X2=5,X3=0
九、编程算法类面试题:
(一)快乐数
1、对于一个正整数,每一次将改数替换为它每个位置上的数字的平方和。然后重复这个过程指导这个数变为1,也可能时无限循环 但始终变不到1。如果这个过程结果为1,那么这个数就是快乐数
如果n是快乐数就返回true;不是,则返回false
思路:
输入:n=19
输出:true
解释:
1²+9²=82
8²+2²=68
6²+8²=100
1²+0²+0²=1
解法:
通过模拟替换的过程来判断一个数是否为快乐数。
如果一个数最终会变成1,那么它就是快乐数;否则,它就不是快乐数
使用一个集合来记录每次替换得到的新数,如果新数已经在集合中出现过,说明出现了循环,那么就可以退出下循环了
(二)最长回文子串
2、给你一个字符串s,找到s中最长的回文子串
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串
思路:
输入:s = "babad"
输出:“bab”
解释:“aba”同样是符合提议的答案
解法:
采用动态规划的方法。定位一个二维数组dp,其中dp[i][j]表示字符串从索引i到j是否为回文串
在计算dp[i][j]时,如果s[i]==s[j]且s[i+1:j-1]是回文串,那么s[i:j]也是回文串
根据上述分析,可以得到状态转移方程:dp[i][j]=(s[i]==s[j]) and dp[i+1][j-1]
在转移时,需要注意字串长度小于2的情况,即i>j-1的情况,此时dp[i][j]应该初始化为True
(三)T秒后青蛙位置
1、给你一棵由n个顶点组成的无向树,顶点编号从1到n。青蛙从顶点1开始起跳。规则如下:
在一秒内,青蛙从它所在的当前顶点跳到另一个未访问过的顶点(如果它们直线相连)。
青蛙无法跳回已经访问过的顶点
如果青蛙可以跳到多个不同的顶点,那么它跳到任意一个顶点上的几率都相同
如果青蛙不能跳到任何未访问过的顶点上,那么它每次跳跃都会停留在原地
无向树的边用数组edges描述,其中edges[i]=[fromi,toi]意味着存在一条直线连通fromi和toi两个顶点的边,返回青蛙在t秒后位于目标顶点的target上的概率
思路:
输入:n=7,edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]],t=2,target =4
输出:1/6
解释:上图显示了青蛙的跳跃路径。青蛙从顶点1起跳,第1秒有1/3的概率跳到顶点2,然后第2秒有1/2的概率跳到顶点4
因此青蛙在2秒后位于顶点4的概率是1/3*1/2=1/6
解法:
对于无向树中的任意一个点,如果它有K个未被访问的相邻节点,那么在下一秒中,青蛙有1/K的概率跳到其中任意一个节点上。如果当前节点是叶子节点 或者没有被访问的相邻节点,那么青蛙在下一秒中只能停留在原地不动
我们可以使用深度优先搜索DFS,从起点开始遍历整个无向树,在遍历过程中计算青蛙到达目标节点的概率
十、股票交易基础知识
1、交易时间:
周一只周五(法定节假日除外)
上午9:30- 11:30
下午13:00-15:00
2、竞价成交:
价格优先,时间优先
上午9:15-9:25 开盘集合竞价(成交量最大的价格)
上午9:30-11:30 下午13:00-14:57连续竞价
下午14:57-15:00收盘集合竞价(成交量最大的价格)
3、交易单位:
报价单位股,交易单位手,100股=1手
股价变动单位最小为0.01元
4、庄家与散户:
庄家:能够影响金融证券市场行情的大户投资者
散户:股市中投入股市资金量较小的个人投资者
5、换手率:
某段时期内的成交量/发行总股数
表征该股票的活跃程度
10-50%非常活跃,低于1%非常不活跃
6、PE:
市盈率,(每股市场价格)/(每股税后利润)
PE越高,该企业越被高估;反之该企业越被低估
7、K线:
将各种股票每日、每周、每月开盘价、收盘价、最高价、最低价等涨跌变化状况,用图形方式表现出来,即蜡烛图
K线需要结合交易量分析
看懂K线不代表能赚钱
8、财务知识:
ROE【收益率】:越高越好
净利润:越高越好
成长性:越改越好
十一、选股:
1、选股:
定义:通过某种手段方式,提供给投资者判断个股的依据,帮助投资者选定个股的方法,选股时股票投资的第一步
作用:选股的好坏,决定能否赚到钱
方法:基本面选股
2、基本面:
定义:分析一家上市公司再发展过程中所面临的外部因素以及其自身的因素,来预测其未来的发展前景,并以此来判断该上市公司的股票是否值得买入
外部因素:经济增长、财政政策、利率变化
内部因素:经营状况、行业地位、财务状况
3、估值方法:
股票估值:基本面选股的核心方法。股票估值能帮助投资者发现现价价值被低估的股票,让他们低买高卖,从而获利
常用指标:每股收益、市盈率、毛利率、净资产收益率、资产负债率、净利润增速
4、选股常用指标说明:
每股收益:
越高越好
代表公司的盈利水平
市盈率:
同行业市盈率越低越好、
14-30倍正常
大于30属于高估
50倍以上存在泡沫
毛利率:
越高越好
毛利率大于50%属于很不错的公司
净资产收益率:
代表公司盈利能力
ROE长期保持在20%以上就是白马股
资产负债率:
适中为好,最好在10%-40%
过高,容易暴雷
过低,发展保守
净利润增速:
代表公司未来成长能力
近3年平均增速在20%以上俗语优质企业
大约50%属于成长股
十二、择时:
1、择时:
定义:买入股票和卖出股票的时机
作用:择时的好坏,决定能够赚到多少钱
方法:技术分析
2、技术分析
定义:从K线形态、成交量、均线、布林带、MACD、KDJ等方面出发分析,他们是反映股价变化的指标
常用工具:K线形态、成交量、均线、布林带、MACD、KDJ
3、K线形态:
定义:K线图蕴含大量信息,能显示股价的强弱、多空双方的力量对比,是技术分析最常见的工具
4、成交量:
在股市中,成交量不仅可以反映出买卖数量的变化,还可以通过成交量看出多空双方的力量变化
5、均线:
将某一段时间的收盘价之和除以该周期所得到的一根平均线。常用的参数有5日、10日、20日、30日、60日
6、布林带:
布林带是一种常用的技术指标,它由三条轨道线组成,其中上下两条线分别可以堪称是价格的压力线和支撑线,在两条线之间是一条价格平均线
7、MACD:
Moving Average COnvergence/Divergence,意味一统移动平均线。它刻画的是股价变化的速度
8、KDJ:
中文名叫随机指标。通过价格波动的真实波幅来反映价格走势的强弱和超买超卖现象,在价格走势的强弱和超买超卖现象,在价格尚未上升或下降之前发出买卖信号的一种技术分析指标,仅适用于短期行情走势分析
十三、量化交易平台:
1、国内量化交易平台:
可为量化交易研发人员提供所需的量化数据、策略框架、回测框架、交易接口等功能,极大提高量化交易初学者的研发效率
2、国内常见平台:
JoinQuant、掘金量化、BigQuant、RiceQuant、TradeBlazer
3、聚宽:
聚宽(JoinQuant)量化交易平台是为量化爱好者(宽客)量身打造的云平台,提供精准的回测功能、高速实盘交易接口、易用的API文档、由易入难的策略库,便于量化研发人员快速实现、使用自己的量化交易策略
4、特点:
时间久、Tick级数据、多交易品种、Python API、实盘交易、社区活跃
5、聚宽量化平台在线使用:
账号注册、试用申请、新建策略、策略回测、模拟交易