一、前言:
用julia搜集了一些数据,并分析它们,最后显示在一个plot上,便于直观判断。
以【中科曙光】为例,plot由四个部分组成
【1】中科曙光历史上每年春季躁动的涨跌幅统计,统计的区间,用竖线画出来。
【2】历史上每年Q3时,基金持股和较上一季报加减仓信息。
【3】历史上每年中,各个季度的营业总收入
【4】历史上每年中,各个季度的归母净利润
二、图形解析:
【1】中科曙光自上市以来,一共经过6次春季躁动(2015-2020),其中2016年下跌,其它年份的春季躁动都是上涨,且涨幅最低8%,最高87%,近四年来的春季躁动,都是连续上涨,平均涨幅25%。
【2】中科曙光股价最近处于低点,半年多来的低点。
【3】2020Q3基金持仓站流通市值8.37%,其中基金加仓0.64%
【4】今年的归母净利润预计略高于去年
【5】今年的营业收入预计与去年持平
结论:中科曙光可以纳入观察,春节前出现信号则买入。
风险:关注贸易战、中美关系、科技制裁、军工、内循环需求、进口替代
下图为【鲁北化工】:大家自己分析,我看了一眼,基金突然加仓,财务也比较靓,股价也不高,建议大家自己深挖。
image.png
三、julia画图代码
我用的是julia1.4版本,GR对中文不支持,以前有版本支持,现在还没update,所以改用pyplot
plot支持中文的设置
pyplot对中文支持的设置如下:
using PyCall
py"""
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['SimHei'] #👈👈👈用来正常显示中文标签👈👈👈
plt.rcParams['axes.unicode_minus']=False #正常显示负号
#plt.rcParams["figure.figsize"] = (20,10) #设置图片的大小
plt.figure(dpi = 300) #设置分辨率
plt.grid(True) #添加图表网格线
"""
把多个plot组成一个plot
"""
画图:把四个图画到一个plot里面
"""
function draw_plot(code,idx,path,stocks_dict,fund_df,revenue_profit_df)
stock_df = stocks_dict[code]
p_kline = draw_kline(stock_df,info_df,tasks_df,code)
q_df = @linq fund_df |> where(:代码1 .== code)
sort!(q_df,:躁动年份)
p_fund = draw_fund_hoding(q_df)
q_df = @linq revenue_profit_df |> where(:代码 .== code)
p_profit = draw_profit(q_df)
p_revenue = draw_revenue(q_df)
p_all = plot(p_kline,p_fund,p_profit, p_revenue, layout = (4, 1), legend = false)
display(p_all)
savefig("$(path)/$(idx)-$(code).svg")
end
代码
using CSV
using DataFrames
using DataFramesMeta
using Dates
using XLSX
using Statistics
using PyCall
include("common.jl")
#👉👉读取股票信息表👈👈
info_df = DataFrame(XLSX.readtable("data/股票信息.xlsx","Sheet1")...)
info_df[!,"stockID"] = info_df.证券代码 .|> stock -> split(stock,".")[1] |> string
stocks = info_df.证券代码 |> unique
info_df |> display
codes = info_df.证券代码 |> unique .|> stock->split(stock,".")[1] |> string
#👉👉读取开平仓的时间点👈👈
kpc_df = DataFrame(XLSX.readtable("data/年份开平仓日期.xlsx","sheet1")...)
kpc_df |> display
kpc_dict = Dict()
for r in eachrow(kpc_df)
kpc_dict[r.年份] = (开仓日期 = r.开仓日期,平仓日期 = r.平仓日期)
end
kpc_dict |> display
#👉👉读取股票的k线信息,装入dict中👈👈
stocks_dict = Dict()
for stock in codes
println(stock)
kind = "股票"
stock = split(stock,".")[1] |> string
if length(stock) < 6 #有港股代码,需要排除
continue #for
end
kline_directory = "D:/juliaWorkSpace/k线" #k线位置
df = read_kline(kind, stock, kline_directory)
#填补空值 ismissing的值,用上一个单元格的值来填补
for idx = 1:size(df)[1]
if idx > 1
for col in names(df)
if ismissing(df[idx, col])
df[idx, col] = df[idx-1, col]
end
end
end
end
stocks_dict[stock] = df
end
stocks_dict
"""
获取收盘价
df:k线数据表
"""
function get_close(df,date)
q_df = @linq df |> where(:day .== date)
if size(q_df,1) >0
q_df[1,"close"]
else
NaN
end
end
#get_close(stock_df,Date("2010-01-11"))
using Plots
#gr()
pyplot()
Plots.GRBackend()
py"""
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #正常显示负号
#plt.rcParams["figure.figsize"] = (20,10) #设置图片的大小
plt.figure(dpi = 300) #设置分辨率
plt.grid(True) #添加图表网格线
"""
"""
获取一只股票的信息
df:股票信息表
code:股票代码【尽量不要加市场后缀】
返回值:(证券简称 = name,所属规模风格类型 = ..,行业 = ..,细分行业 = ..)
get_stock_info(info_df,"600352").证券简称
"""
function get_stock_info(df,code)
q_df = @linq info_df |> where(occursin.(Ref(code),:证券代码))
if size(q_df,1) > 0
name = q_df[1,"证券简称"]
style = q_df[1,"所属规模风格类型"]
industry = q_df[1,"行业"]
sub_industry = q_df[1,"细分行业"]
else
name = ""
style = ""
industry = ""
sub_industry = ""
end
return(证券简称 = name,所属规模风格类型 = style,行业 = industry,细分行业 = sub_industry)
end
"""
未达到指定的长度,字符串在尾部用空值补足
str:给定的字符串
len:要是之达到的长度
fill_string("-5.64",8)|>println
"""
function fill_string(str,len)
if length(str) > len
throw("$(str)的长度超过了$(len)")
end
fill_num = len - length(str)
final_str = str
for i in 1:fill_num
final_str = string(final_str," ")
end
final_str
end #end fill_string
"""
获取股票躁动的历年信息
df:已经统计完成的春季躁动表
code:股票代码
"""
function get_stock_tj_info(df, code)
q_df = @linq df |> where(occursin.(Ref(code), :证券代码))
if size(q_df, 1) > 0
最近x年连胜 = q_df[1,:最近x年连胜]
最近连胜平均涨跌幅 = q_df[1,:最近连胜平均涨跌幅]
期间x年连胜 = q_df[1,:期间x年连胜]
期间连胜平均涨跌幅 = q_df[1,:期间连胜平均涨跌幅]
y2011 = q_df[1,:y2011]
y2012 = q_df[1,:y2012]
y2013 = q_df[1,:y2013]
y2014 = q_df[1,:y2014]
y2015 = q_df[1,:y2015]
y2016 = q_df[1,:y2016]
y2017 = q_df[1,:y2017]
y2018 = q_df[1,:y2018]
y2019 = q_df[1,:y2019]
y2020 = q_df[1,:y2020]
else
end
return(
最近x年连胜 = 最近x年连胜,
最近连胜平均涨跌幅 = 最近连胜平均涨跌幅,
期间x年连胜 = 期间x年连胜,
期间连胜平均涨跌幅 = 期间连胜平均涨跌幅,
y2011 = y2011,
y2012 = y2012,
y2013 = y2013,
y2014 = y2014,
y2015 = y2015,
y2016 = y2016,
y2017 = y2017,
y2018 = y2018,
y2019 = y2019,
y2020 = y2020
)
end #function get_stock_tj_info
"""
生成各年涨跌幅的信息
res = get_stock_tj_info(tasks_df,"600352")
get_year_gain_str(res) |>println
"""
function get_year_gain_str(res)
year_gain_str = ""
年份 = ""
涨跌 = ""
for y in 2011:2020
value = res[Symbol("y$(y)")]
if typeof(value) == String
value = parse(Float64,value)
end
value = isnan(value) ? 0.0 : value #有NaN的值
value = round(value,digits = 2)
年份 = string(年份,fill_string("$(y)",8),"|")
涨跌 = string(涨跌,fill_string("$(value)",8),"|")
end
year_gain_str = string(year_gain_str,"\n","年份 :|",年份)
year_gain_str = string(year_gain_str,"\n","涨跌 :|",涨跌)
end #function get_year_gain_str
"""
春季躁动画图分析
"""
function draw_kline(df, info_df, tasks_df, code)
#股票简要信息
info = get_stock_info(info_df, code)
title_text = "【$(code)】 【$(info.证券简称)】 【$(info.所属规模风格类型)】 【$(info.行业)】 【$(info.细分行业)】"
res = get_stock_tj_info(tasks_df, code)
最近x年连胜 = res.最近x年连胜
最近连胜平均涨跌幅 = res.最近连胜平均涨跌幅
title_text = string(title_text, "\n最近x年连胜:$(最近x年连胜),平均涨跌幅:$(最近连胜平均涨跌幅)")
期间x年连胜 = res.期间x年连胜
期间连胜平均涨跌幅 = res.期间连胜平均涨跌幅
title_text = string(title_text, "\n期间x年连胜:$(期间x年连胜),平均涨跌幅:$(期间连胜平均涨跌幅)")
res = get_stock_tj_info(tasks_df, code)
year_gains = get_year_gain_str(res)
title_text = string(title_text, "\n", year_gains)
#画收盘价的线
x = df.day
y = df.close
p1 = plot(
x,
y,
w = 1,
title = title_text,
size = (3000, 1500),
legend = false,
bg = RGB(0.2, 0.2, 0.2),
)
#画各个春季躁动的起始和结束分隔线
for year = 2011:2020
begin_date = kpc_dict[year].开仓日期
end_date = kpc_dict[year].平仓日期
if df.day[1] <= begin_date
x1 = [begin_date, begin_date] #x轴刻度值
close1 = get_close(df, begin_date)
y1 = [0, close1]
plot!(x1, y1, w = 1, color = :green)
x2 = [end_date, end_date]
close2 = get_close(df, end_date)
y2 = [0, close2]
plot!(x2, y2, w = 1, color = :red)
end
end
#画每年第一个交易日的一个竖线,用于分隔各年的k线
for year = 2011:2020
start_date = "$(year)-01-01" |> Date
end_date = "$(year)-12-31" |> Date
q_df = @linq df |> where(start_date .<= :day .<= end_date)
if size(q_df, 1) > 0
date1 = q_df[1, "day"]
x3 = [date1, date1]
close3 = get_close(df, date1)
y3 = [0, close3]
plot!(x3, y3, w = 1, color = :yellow)
end
end
#savefig(p1, "data/k线图/$(idx)_$(code).svg")
#display(p1)
return p1
end
#读取基金持仓的信息
fund_df = CSV.read("data\\主流程5 增加基金持股信息到地4步的选股结果\\输入数据\\基金持仓和加仓信息.csv")
fund_df |> names
fund_df[!,"代码1"] = fund_df.代码 .|> code->split(code,".")[1] |>string
"""
画某股票被基金持股的年度对比图
"""
function draw_fund_hoding(q_df)
x = [y for y in 2010:2021] #年份
y = begin #年份 - 持股占流通股比(%)
ary = []
for year in x
tmp_df = @linq q_df |> where(:躁动年份 .== year )
if size(tmp_df,1) > 0
push!(ary,tmp_df[1,"持股占流通股比(%)"])
else
push!(ary,0.0)
end
end
ary
end
holding2020q3,chg2020q3 = begin
df2020q3 = @linq q_df |> where(:躁动年份 .== 2021)
if size(df2020q3,1) > 0
(df2020q3[1,"持股占流通股比(%)"],df2020q3[1,"加减仓占流通股比(%)"])
else
(0.0,0.0)
end
end
title_text = "各年Q3公告时,基金持仓占流通市值百分比"
holding_ratio = holding2020q3
chg_ratio = chg2020q3
title_text = string(title_text,"\n 2020 Q3 持仓占比:$(holding_ratio),相较2020 Q2持仓变化的股份占流通市值百分比:$(chg_ratio)")
p1 = plot(
x,
y,
w = 1,
title = title_text,
#color = colors,
seriestype = bar, # :scatter,
size = (3000, 1500),
legend = false,
bg = RGB(0.2, 0.2, 0.2),
)
#savefig("data/p1.svg")
#display(p1)
return p1
end
q_df = @linq fund_df |> where(:代码1 .== "002371")
sort!(q_df,:躁动年份)
p2 = draw_fund_hoding(q_df)
"""
画出各个季度的财报营业总收入
输入:q_df 包含列名
x = q_df.report_date 财报日期
y = q_df.total_operating_revenue 报告的净利润
不用的季度采用不同的颜色
"""
function draw_revenue(q_df)
x = q_df.report_date
y = q_df.total_operating_revenue |> ary -> Missings.replace(ary,0.0) |> collect #替换missing值
title_text = "营业总收入,每个季度累加\n hongse = q1,橙色 = q2,黄色 = q3,绿色 = q4"
colors = []
for d in q_df.report_date
m = d |> month
if m == 3
push!(colors, "red")
elseif m == 6
push!(colors, "orange")
elseif m == 9
push!(colors, "yellow")
elseif m == 12
push!(colors, "green") #第四季度变成绿色,用于区分各年的财报
else
end
end
p1 = plot(
x,
y,
w = 1,
title = title_text,
color = colors,
seriestype = bar, # :scatter,
size = (3000, 1500),
legend = false,
bg = RGB(0.2, 0.2, 0.2),
)
#display(p1)
return p1
end
"""
画出各个季度的财报归母净利润
输入:q_df 包含列名
x = q_df.report_date 财报日期
y = q_df.np_parent_company_owners 报告的净利润
不用的季度采用不同的颜色
"""
function draw_profit(q_df)
x = q_df.report_date
y = q_df.np_parent_company_owners
title_text = "归母净利润,每个季度累加\n hongse = q1,橙色 = q2,黄色 = q3,绿色 = q4"
colors = []
for d in q_df.report_date
m = d |> month
if m == 3
push!(colors, "red")
elseif m == 6
push!(colors, "orange")
elseif m == 9
push!(colors, "yellow")
elseif m == 12
push!(colors, "green") #第四季度变成绿色,用于区分各年的财报
else
end
end
p1 = plot(
x,
y,
w = 1,
title = title_text,
color = colors,
seriestype = bar, # :scatter,
size = (3000, 1500),
legend = false,
bg = RGB(0.2, 0.2, 0.2),
)
#display(p1)
return p1
end
#需要打印的k线
tasks_df = DataFrame(XLSX.readtable("data/需要打印k线的春季躁动列表.xlsx","Sheet1")...)
sort!(tasks_df,[:最近x年连胜,:最近连胜平均涨跌幅],rev = true)
task_codes = tasks_df.证券代码 .|> code -> split(code,".")[1] |> string
#读取《营收和净利指标.csv》表
revenue_profit_df = CSV.read("data/主流程-7-增加各年各季度的营收和归母净利润/输入数据/营收和净利指标.csv")
revenue_profit_df[!, "代码"] = revenue_profit_df.code .|> code -> split(code, ".")[1] |> string
#读取基金持仓的信息
fund_df = CSV.read("data\\主流程5 增加基金持股信息到地4步的选股结果\\输入数据\\基金持仓和加仓信息.csv")
fund_df[!,"代码1"] = fund_df.代码 .|> code->split(code,".")[1] |>string
"""
画图:把四个图画到一个plot里面
"""
function draw_plot(code,idx,path,stocks_dict,fund_df,revenue_profit_df)
stock_df = stocks_dict[code]
p_kline = draw_kline(stock_df,info_df,tasks_df,code)
q_df = @linq fund_df |> where(:代码1 .== code)
sort!(q_df,:躁动年份)
p_fund = draw_fund_hoding(q_df)
q_df = @linq revenue_profit_df |> where(:代码 .== code)
p_profit = draw_profit(q_df)
p_revenue = draw_revenue(q_df)
p_all = plot(p_kline,p_fund,p_profit, p_revenue, layout = (4, 1), legend = false)
display(p_all)
savefig("$(path)/$(idx)-$(code).svg")
end
code = "600352"
idx = 1
path = "data/k线图"
draw_plot(code,idx,path,stocks_dict,fund_df,revenue_profit_df)
tasks_df = DataFrame(XLSX.readtable("data/需要打印k线的春季躁动列表.xlsx","Sheet1")...)
sort!(tasks_df,[:最近x年连胜,:最近连胜平均涨跌幅],rev = true)
task_codes = tasks_df.证券代码 .|> code -> split(code,".")[1] |> string
code = "600603"
idx = 1
path = "data/k线图"
draw_plot(code,idx,path,stocks_dict,fund_df,revenue_profit_df)
codes = task_codes[1:434]
for (idx,code) in zip(1:length(codes),codes)
println(code)
draw_plot(code,idx,path,stocks_dict,fund_df,revenue_profit_df)
idx += 1
end
"""
todo:
(*)增加Q3时基金持股信息:【持股家数】,【占流通比】
(*)增加年份的notation
(*)增加财务信息,各年的各季度的【营收】和【利润】
(*)更新k线数据,更新到最新的k线
"""
#读取判断条件,进行过滤
filter_df_finaces = CSV.read("data/单独流程 - 画k线观察各个躁动年份/输入数据/2020年三个季度净利润同比增长率为正.csv")
filter_df_fund_hold = CSV.read("data/单独流程 - 画k线观察各个躁动年份/输入数据/基金持仓筛选后的股票.csv")
filter_df_fund_hold |> names |> println
codes1 = filter_df_fund_hold.代码 |> unique |> Set .|> item->split(item,".")[1] |> string
codes2 = filter_df_finaces.代码 |> unique |> Set .|> item->split(item,".")[1] |> string
intersect(codes1,codes2)
#打印k线
tasks_df = DataFrame(CSV.read("data/单独流程 - 画k线观察各个躁动年份/截至当前-已经连续X年取胜且满足[财报]和[基金]持股的条件.csv"))
sort!(tasks_df,[:最近x年连胜,:最近连胜平均涨跌幅],rev = true)
task_codes = tasks_df.证券代码 .|> code -> split(code,".")[1] |> string
code = "600519"
stock_df = stocks_dict[code]
draw(stock_df,info_df,tasks_df,code,1)
codes = task_codes
for (idx,task_code) in zip(1:length(codes),codes)
println(task_code)
stock_df = stocks_dict[task_code]
draw(stock_df, info_df, tasks_df, task_code,idx)
idx += 1
end
网友评论