一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、学习软件
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
三、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
if end\_date\_ < start\_date\_:
sys.exit("起始时间应该大于结束时间")
if start\_date\_ > now:
sys.exit("起始时间应该大于当前时间")
if end\_date\_ > now:
end\_date = now.strftime(DATE\_FORMAT)
except Exception:
traceback.print\_exc("")
sys.exit("传入的start\_date\[%s\]或end\_date\[%s\]时间格式不正确, 格式应该像20200101" % (start\_date, end\_date))
def worker(ts\_code):
fn = partial(ts.pro\_bar, ts\_code=ts\_code, adj='qfq', start\_date=start\_date, end\_date=end\_date)
return retry(fn)
pool = ThreadPoolExecutor(max\_workers=worker\_size)
print("准备开始获取 %s到%s 的股票数据" % (start\_date, end\_date))
# 不指定任何参数会获取5000条最近的数据,ts\_code会重复
day = pro.daily()
# 固定顺序,set是无法包装有序的
all\_ts\_code = list(set(day.ts\_code))
fs\_lst = \[\]
for ts\_code in all\_ts\_code:
fs\_lst.append(pool.submit(worker, ts\_code))
# break
for ts\_code, fs in zip(all\_ts\_code, fs\_lst):
# 如果有异常或者结果为空的话
if fs.exception() or not isinstance(fs.result(), pd.DataFrame):
print(fs.exception())
sys.exit("在交易日\[%s\]超过重试最大的次数也没有获取到数据" % trade\_date)
df = fs.result()
# %timeit df.sort\_index()
# 192 µs ± 3.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# %timeit df.sort\_index(inplace=True)
# 2.54 µs ± 177 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
df.sort\_index(inplace=True, ascending=False)
if not isinstance(df, pd.DataFrame):
sys.exit("在股票\[%s\]超过重试最大的次数也没有获取到数据" % ts\_code)
save\_to\_csv({ts\_code: df}, data\_path=data\_path)
if debug:
print("股票\[%s\]历史数据下载保存完成" % ts\_code)
end\_time = datetime.now()
print("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*")
print("下载完成, 共花费时间%s" % (end\_time - start\_time))
print("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*")
我感觉我写了好多注释以及一些方法之间性能对比,关于各个方法之间的性能对比大家还是需要注意的,因为虽然平时感受不出来,但是在较多次数的循环的时候就会发现性能差异了。
至此需要的历史数据就得到了。
如果对读写速度很在意的话,存储在sqlite数据库或者其他其他数据会快很多。
### 股票池的选择条件
无论是主观交易还是量化交易,选股的方式个人认为大概分为以下三类。
1. 技术选股
通过技术指标比如MACD, KDJ或者K线形态等技术指标来选股。
2. 基本面选股
通过财务报表或者一些金融指标来选股。
3. 消息选股
新闻消息或者小道消息选股。
本文主要集中在以下几种方式
1. 形态选股
通过k线的形态找到股票中的十字星等形态。
2. 交易额/流通股本选股
通过对交易额或者流通股本排序选择前面的股票。
3. 相似度选股
通过选定基准股票趋势,发现相似的股票。
4. 趋势选股
挑选最近六个月股票趋势向上的股票。
#### 形态选股
股票的形态多种多样,这里以选择股票中的黄昏(早晨)十字星为例。
黄昏十字星与早晨十字星的区别在于所处趋势不一样。
图示如下:
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9wMS10dC5ieXRlaW1nLmNvbS9sYXJnZS9wZ2MtaW1hZ2UvYjlkZjE0ODA2NTliNDJiOWFkMzQ0YmVkNmMxODM0YmY?x-oss-process=image/format,png)
如果需要程序判断,那么这些长度需要量化,不能模棱两可。所以根据十字星的定义,量化如下:
实体长度: 超过2.5%才算长实体,而且上下影线不能超过0.3%
十字星: 实体长度不超过1.5%
趋势: 包括十字星在内往前数6根k线,其中的第1根k线收盘价均小于它后面4根收盘价为向上趋势,反之趋势向下,并且幅度超过2.5%。
这里我只是主观的量化没有任何交易经验的选择,如果不认同的话,可以自行修改代码。
代码如下:
def select_doji():
# fp = “by_ts_code/600249.SH-.csv”
fp = “by_ts_code/300130.SZ-.csv”
df = pd.read_csv(fp, index_col=“trade_date”, parse_dates=[“trade_date”])
df = df[[“open”, “high”, “low”, “close”]]
# k线数量
k\_size = 6
# 起始幅度大小
treand\_threshold = 0.025
# 长实体最小长度
entity\_length\_threshold = 0.025
# 长实体上下最大影线长度
entity\_shadow\_line\_length\_threshold = 0.03
# 十字星实体长度最大长度
doji\_entity\_length\_threshold = 0.015
# 十字星上下影线长度最小长度
# doji\_shadow\_line\_length\_threshold = 0.005
trend\_map = {1: "向上", -1: "向下"}
def up\_or\_down\_trend(row):
"""1代表向上, -1代表向下, 0代表震荡"""
first = row\[0\]
last = row\[-1\]
if all(first > row\[1:\]) and first > (last \* treand\_threshold):
return -1
elif all(first < row\[1:\]) and last > (first \* treand\_threshold):
return 1
else:
return 0
df\["trend"\] = df.close.rolling(k\_size).apply(up\_or\_down\_trend, raw=True)
df.fillna(value=0, inplace=True)
def k\_sharp(k):
"""返回k线的上下影线长度, 实体长度"""
open\_, high, low, close = k\[:4\]
if open\_ > close:
upper\_line\_length = (high - open\_) / high
lower\_line\_length = (close - low) / close
entity\_length = (open\_ - close) / open\_
else:
upper\_line\_length = (high - close) / high
lower\_line\_length = (open\_ - low) / open\_
entity\_length = (close - open\_) / close
return upper\_line\_length, lower\_line\_length, entity\_length
def is\_up\_or\_down\_doji(k\_lst, trend):
# open, high, low, close
if len(k\_lst) != 3:
sys.exit("判断十字星需要三根K线")
is\_ok = False
k1, k2, k3 = k\_lst
# 判断是否跳空
# 通过high, close过于严格
if trend > 0:
# 趋势向上时,最低点是否大于两个实体的最高价
if k2\[0\] < k1\[1\] or k2\[0\] < k3\[1\]:
# if k2\[0\] < k1\[1\] :
return is\_ok
else:
# 趋势向下时,最高点是否小于两个实体的最高价
if k2\[0\] > k1\[2\] or k2\[0\] > k3\[2\]:
return is\_ok
k1\_sharp = k\_sharp(k1)
# print("k1 sharp")
# print(k1\_sharp)
# 判断是否为长实体
if (k1\_sharp\[2\] < entity\_length\_threshold
or k1\_sharp\[0\] > entity\_shadow\_line\_length\_threshold
or k1\_sharp\[1\] > entity\_shadow\_line\_length\_threshold):
return is\_ok
k3\_sharp = k\_sharp(k3)
# print("k3 sharp")
# print(k3\_sharp)
if (k3\_sharp\[2\] < entity\_length\_threshold
or k3\_sharp\[0\] > entity\_shadow\_line\_length\_threshold
or k3\_sharp\[1\] > entity\_shadow\_line\_length\_threshold):
return is\_ok
# print("ok")
# 判断是否为十字星
k2\_sharp = k\_sharp(k2)
# print("k2 sharp")
# print(k2\_sharp)
# 实体长度不超过0.2%, 上下影线长度超过0.6%, 如果规定上下影线的长度不太好找
# if (k2\_sharp\[2\] > doji\_entity\_length\_threshold
# or k2\_sharp\[0\] < doji\_shadow\_line\_length\_threshold
# or k2\_sharp\[1\] < doji\_shadow\_line\_length\_threshold):
if k2\_sharp\[2\] > doji\_entity\_length\_threshold:
return is\_ok
return True
df\_values = df.values
ret = \[\]
for index in range(len(df\_values)):
if index < k\_size:
continue
trend = df\_values\[index - 1\]\[-1\]
if trend == 0:
continue
val\_slice = slice(index-2, index+1)
k\_lst = df\_values\[val\_slice\]
if is\_up\_or\_down\_doji(k\_lst, trend):
ret.append(index-1)
print("在>>%s<<<找到趋势为\[%s\]的十字星" % (df.index\[index-1\], trend\_map\[trend\]))
if not ret:
print("没有发现任何十字星")
ax = ohlc\_plot(df\[\["open", "high", "low", "close"\]\])
for i in ret:
# print(i)
mark\_x = df.index\[i\]
# mark\_y = df.loc\[mark\_x\].low
# print(mark\_x, mark\_y)
ax.axvline(mark\_x)
plt.show()
return ret
结果如下:
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9wMS10dC5ieXRlaW1nLmNvbS9sYXJnZS9wZ2MtaW1hZ2UvNzVlYWUyYmVmYTk2NDUwZDlkNTBlYTU0YWViODRiNGY?x-oss-process=image/format,png)
说实话标准的不太好找,所以代码的条件设置不是很严格。
形态选股很有意思,以后有机会单独出一篇文章。
#### 交易额/流通股本选股
通过交易额过滤,选择股票最近一百个交易日的成交额平均值,然后进行排序。
交易额排序
def select_by_amount(data_path, top_size=20):
# 或许交易日比较好
day_range = 100
all\_df = load\_all\_local\_data(data\_path, tail\_size=day\_range)
ret = \[\]
for ts\_code, df in all\_df.items():
df\["amount\_avg"\] = df.amount.rolling(day\_range).mean()
amount\_avg = df\["amount\_avg"\]\[-1\]
# NaN的布尔值为True, 所以需要np.isnan判断
if np.isnan(amount\_avg):
continue
ret.append((ts\_code, amount\_avg))
ret.sort(key=lambda x:x\[1\])
print("交易额排名前%s的结果如下" % top\_size)
print(ret\[-top\_size:\])
return ret\[-top\_size:\]
结果如下。
[(‘002714.SZ’, 2162871.9387400015), (‘000002.SZ’, 2294273.739109999), (‘002460.SZ’, 2372975.2177099977), (‘600745.SH’, 2461243.4350499995), (‘601990.SH’, 2551214.2825800003), (‘603986.SH’, 2679324.4020000002), (‘600703.SH’, 2759167.96963), (‘002456.SZ’, 2759314.642220001), (‘000651.SZ’, 2782179.0211499995), (‘000100.SZ’, 2853012.22389), (‘002185.SZ’, 3149773.6836400027), (‘000858.SZ’, 3168871.2845699983), (‘002475.SZ’, 3392269.47999), (‘300750.SZ’, 3511882.7076800014), (‘600030.SH’, 4039920.83439), (‘000725.SZ’, 4189700.4488400007), (‘300059.SZ’, 4447245.855129998), (‘600519.SH’, 4448082.42745), (‘601318.SH’, 4892206.13003), (‘000063.SZ’, 5128169.27109)]
流通市值排序
def select_by_float_market_value(trade_date, top_size=20):
df = pro.daily_basic(ts_code=‘’, trade_date=trade_date, fields=“ts_code,close,float_share”)
ret = \[\]
for row in df.values:
ts\_code = row\[0\]
float\_market\_value = row\[1\] \* row\[2\]
if np.isnan(float\_market\_value) or not float\_market\_value:
continue
ret.append((ts\_code, float\_market\_value))
ret.sort(key=lambda x:x\[1\])
print("流通市值名前%s的结果如下" % top\_size)
print(ret\[-top\_size:\])
return ret\[-top\_size:\]
结果如下
交易额排名前20的结果如下
[(‘000002.SZ’, 24443367.828188002), (‘000001.SZ’, 25072232.462559998), (‘601088.SH’, 26237241.386405), (‘600000.SH’, 28497216.593586), (‘601166.SH’, 30952865.369478), (‘000651.SZ’, 33204757.629185997), (‘603288.SH’, 36720702.433056), (‘600900.SH’, 36894000.0), (‘000333.SZ’, 39063915.66100799), (‘600028.SH’, 40612052.69455), (‘600276.SH’, 42312945.987192), (‘000858.SZ’, 54753808.6884), (‘601628.SH’, 54786707.43), (‘600036.SH’, 69375140.114727), (‘601857.SH’, 70759948.006466), (‘601988.SH’, 72081806.077332), (‘601318.SH’, 75958643.459976), (‘601288.SH’, 99096634.04564801), (‘601398.SH’, 136154167.33219498), (‘600519.SH’, 166848191.796)]
这种方式比较简单,但是一般还需要一些其他的条件相互配合。
**另外怕大家不会使用,直接给大家准备了写好的,直接下载打开即可使用!**
**源码放在百度云盘上了需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】**
![](https://img-blog.csdnimg.cn/img_convert/d440a77c65cd426371caeade1a63e197.png)/>
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
**另外怕大家不会使用,直接给大家准备了写好的,直接下载打开即可使用!**
**源码放在百度云盘上了需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】**
[外链图片转存中...(img-Yvqilmww-1715645412485)]/>
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**