feat: 🌈 output all stock hold fund detail

main
jackluson 3 years ago
parent d467158ede
commit bd7a535eb3

2
.gitignore vendored

@ -6,8 +6,10 @@ code-record/*
*$py.class
.vscode/
*fund_morning_star.csv
src/temp_update_*
abnormal
demo/
outcome/stocks/
output/json/
!output/xlsx/
.env

Binary file not shown.

@ -14,7 +14,7 @@ import sys
from pprint import pprint
sys.path.append('../')
sys.path.append(os.getcwd() + '/src')
from utils.index import get_quarter_index
from utils.index import get_quarter_index, fisrt_match_condition_from_list
from sql_model.fund_query import FundQuery
@ -50,12 +50,16 @@ class FundStatistic:
code_dict = dict()
for result in results:
# print(result)
for index in range(1, len(result), 2):
for index in range(3, len(result), 3):
code = result[index]
name = result[index + 1] # 仅以股票名称为key兼容港股A股
# key = str(code) + '-' + str(name)
key = str(name)
if code == None or name == None:
#print('index', index, 'code', code, 'name', name)
#print('基金名称', result[1],'基金代码', result[0])
continue
key = fisrt_match_condition_from_list(list(code_dict), code)
if key == None and code and name:
key = str(code) + '-' + str(name)
if(key in code_dict and code != None):
code_dict[key] = code_dict[key] + 1
else:
@ -66,19 +70,67 @@ class FundStatistic:
if value > filter_count and key != None:
filer_dict[key] = value
# print(key + ":" + str(value))
list = sorted(filer_dict.items(), key=lambda x: x[1], reverse=True)
return list
return sorted(filer_dict.items(), key=lambda x: x[1], reverse=True)
def all_stock_fund_count_and_details(self, *, quarter_index=None, fund_code_pool=None, filter_count=100):
"""查询某一个季度基金的十大持仓并对持仓股票进行汇总统计并根据filter_count进行过滤
Args:
quarter_index (string, optional): [description]. Defaults to None.取self.quarter_index
fund_code_pool (string[], optional): [description]. Defaults to None. 传入查询的基金池为None默认查询全部
filter_count (int, optional): [description]. Defaults to 100. 过滤门槛过滤掉一些持仓低的股票
Returns:
tuple[]: 每只股票的名称以及对应持仓基金个数的list
"""
quarter_index = quarter_index if quarter_index else self.quarter_index
results = self.each_query.select_top_10_stock(
quarter_index,
fund_code_pool
)
code_dict = dict()
for result in results:
#print(result)
fund_info = {
'基金代码': result[0],
'基金名称': result[1],
'股票总仓位': result[2],
}
for index in range(3, len(result), 3):
code = result[index]
name = result[index + 1] # 仅以股票名称为key兼容港股A股
portion = result[index + 2] # 仅以股票名称为key兼容港股A股
if code == None or name == None:
continue
key = fisrt_match_condition_from_list(list(code_dict), code)
if key == None and code and name:
key = str(code) + '-' + str(name)
#key = str(name)
if(key in code_dict and code != None):
code_dict[key]['count'] = code_dict[key]['count'] + 1
code_dict[key]['fund_list'].append({
**fund_info,
'仓位占比': portion,
'仓位排名': int(index / 3)
})
else:
code_dict[key] = {
'count': 1,
'fund_list': [{
**fund_info,
'仓位占比': portion,
'仓位排名': int(index / 3)
}]
}
#for key, value in code_dict.items():
# print('key, value', key, value)
return sorted(code_dict.items(), key=lambda x: x[1]['count'], reverse=True)
# 分组查询特定股票的每个季度基金持有总数
def item_stock_fund_count(self, stock_name, fund_code_pool=None):
return self.each_query.select_special_stock_fund_count(stock_name, fund_code_pool)
def item_stock_fund_count(self, stock_code, fund_code_pool=None):
return self.each_query.select_special_stock_fund_count(stock_code, fund_code_pool)
def select_fund_pool(self, *, morning_star_rating_5="", morning_star_rating_3="", **args):
# print("morning_star_rating_5", morning_star_rating_5)
# print("morning_star_rating_3", morning_star_rating_3)
# print("args", args)
# morning_star_rating_5 = 5
return self.each_query.select_certain_condition_funds(
morning_star_rating_5=morning_star_rating_5,
morning_star_rating_3=morning_star_rating_3,

@ -9,27 +9,58 @@ Author: luxuemin2108@gmail.com
Copyright (c) 2020 Camel Lu
'''
import time
import re
from pprint import pprint
import pandas as pd
from fund_info.statistic import FundStatistic
from utils.index import get_last_quarter_str
from openpyxl import load_workbook
import os
def get_fund_code_pool():
# fund_code_pool = ['000001', '160133', '360014', '420002',
# '420102', '000409', '000418', '000746',
# '000751', '000884', '000991', '001043',
# '001054', '001104', '001410', '001473',
# '519714', '000003', '000011', '000029']
morning_star_rating_5_condition = {
'value': 4,
'operator': '>='
}
morning_star_rating_3_condition = {
'value': 5,
'operator': '='
}
last_year_time = time.localtime(time.time() - 365 * 24 * 3600)
last_year_date = time.strftime('%Y-%m-%d', last_year_time)
condition_dict = {
'morning_star_rating_5': morning_star_rating_5_condition,
'morning_star_rating_3': morning_star_rating_3_condition,
# 'manager_start_date': '2020-05-25'
}
fund_code_pool = each_statistic.select_fund_pool(
# **condition_dict,
#)
return fund_code_pool
def stocks_compare(stock_list, fund_code_pool=None):
each_statistic = FundStatistic()
filter_list = []
for stock in stock_list:
stock_name = stock[0]
stock_code = stock[0].split('-', 1)[0]
stock_name = stock[0].split('-', 1)[1]
stock_sum = stock[1]
stock_quarter_count_tuple = each_statistic.item_stock_fund_count(
stock_name,
stock_code,
fund_code_pool
)
try:
last_count_tuple = stock_quarter_count_tuple[len(
stock_quarter_count_tuple) - 2]
except:
print('该股票查询异常', stock_name)
print("stock_quarter_count_tuple", stock_quarter_count_tuple)
print('该股票查询异常', stock_code, stock_name)
continue
last_stock_sum = last_count_tuple[0] # 选出上一个季度的
@ -55,48 +86,61 @@ def stocks_compare(stock_list, fund_code_pool=None):
# print(item_tuple)
return filter_list
if __name__ == '__main__':
each_statistic = FundStatistic()
# fund_code_pool = ['000001', '160133', '360014', '420002',
# '420102', '000409', '000418', '000746',
# '000751', '000884', '000991', '001043',
# '001054', '001104', '001410', '001473',
# '519714', '000003', '000011', '000029']
morning_star_rating_5_condition = {
'value': 4,
'operator': '>='
}
morning_star_rating_3_condition = {
'value': 5,
'operator': '='
}
last_year_time = time.localtime(time.time() - 365 * 24 * 3600)
last_year_date = time.strftime('%Y-%m-%d', last_year_time)
condition_dict = {
'morning_star_rating_5': morning_star_rating_5_condition,
'morning_star_rating_3': morning_star_rating_3_condition,
# 'manager_start_date': '2020-05-25'
}
fund_code_pool = each_statistic.select_fund_pool(
**condition_dict,
)
# pprint(fund_code_pool)
def top100_stock(each_statistic, threshold=80):
quarter_index = get_last_quarter_str()
last_quarter_index = get_last_quarter_str(2)
stock_top_list = each_statistic.all_stock_fund_count(
quarter_index="2021-Q1",
fund_code_pool=fund_code_pool,
filter_count=5)
quarter_index=quarter_index,
filter_count=threshold)[:100]
# print('2020-Q4 top 100 股票')
pprint(stock_top_list)
print(len(stock_top_list))
#print(len(stock_top_list))
filter_list = stocks_compare(stock_top_list)
#pprint(filter_list)
pprint(len(filter_list))
df_filter_list = pd.DataFrame(filter_list, columns=[
'名称', quarter_index + '持有数量(只)', last_quarter_index + '持有数量(只)', '环比', '环比百分比', '升Or降'])
df_filter_list.to_excel(
'./outcome/strategy/top100.xlsx', sheet_name=quarter_index + '基金重仓股T100')
# filter_list = stocks_compare(stock_top_list, fund_code_pool)
def all_stock(each_statistic, threshold=0):
quarter_index = "2021-Q1"
stock_list = each_statistic.all_stock_fund_count_and_details(
quarter_index=quarter_index,
filter_count=threshold)
for i in range(0, len(stock_list)):
stock = stock_list[i]
stock_name_code = stock[0]
stock_code = stock_name_code.split('-', 1)[0]
path = 'other'
if bool(re.search("^\d{5}$", stock_code)):
path = 'hk'
elif bool(re.search("^\d{6}$", stock_code)):
path = 'a'
hold_fund_count = stock[1]['count']
hold_fund_list = stock[1]['fund_list']
df_list = pd.DataFrame(hold_fund_list)
stock_name_code = stock_name_code.replace('/', '-')
path = './outcome/stocks/' + path + '/' + stock_name_code + '.xlsx'
path = path.replace('\/', '-')
if os.path.exists(path):
writer = pd.ExcelWriter(path, engine='openpyxl')
book = load_workbook(path)
writer.book = book
df_list.to_excel(
writer, sheet_name=quarter_index)
writer.save()
writer.close()
else:
df_list.to_excel(
path, sheet_name=quarter_index)
if __name__ == '__main__':
each_statistic = FundStatistic()
# 获取重仓股
top100_stock(each_statistic)
# pprint(filter_list)
# pprint(len(filter_list))
# df_filter_list = pd.DataFrame(filter_list, columns=[
# '名称', '2021-Q1持有数量', '2020-Q4持有数量', '环比', '环比百分比', '升Or降'])
# print(df_filter_list)
# df_filter_list.to_excel(
# './output/xlsx/top100-2021_q1_vs_2020_q4.xlsx', sheet_name='top100')
# 所有股票的基金持仓细节
#all_stock(each_statistic)

@ -9,12 +9,15 @@ Copyright (c) 2021 Camel Lu
'''
from sql_model.fund_query import FundQuery
import pandas as pd
from openpyxl import load_workbook
from openpyxl import load_workbook,Workbook
from openpyxl.utils import get_column_letter
from utils.index import get_last_quarter_str
from pprint import pprint
if __name__ == '__main__':
each_query = FundQuery()
quarter_index = '2020-Q4'
# 输出高分基金
def output_high_score_funds(each_query,quarter_index=None):
if quarter_index == None:
quarter_index = get_last_quarter_str()
high_score_funds = each_query.select_high_score_funds(
quarter_index=quarter_index)
columns_bk = ['代码', '名称', '季度', '总资产', '现任基金经理管理起始时间', '投资风格', '三月最大回撤', '六月最大回撤', '夏普比率', '阿尔法系数', '贝塔系数',
@ -34,7 +37,24 @@ if __name__ == '__main__':
writer = pd.ExcelWriter(path, engine='openpyxl')
book = load_workbook(path)
writer.book = book
df_high_score_funds.to_excel(writer, sheet_name=quarter_index)
writer.save()
writer.close()
if __name__ == '__main__':
#each_query = FundQuery()
#quarter_index = '2020-Q4'
#output_high_score_funds()
dest_filename = 'empty_book.xlsx'
#wb = Workbook(dest_filename)
wb = load_workbook(filename = 'empty_book.xlsx')
ws = wb.active
print("ws", ws)
#ws.merge_cells('A2:D2')
ws.merge_cells(start_row=2, start_column=1, end_row=4, end_column=4)
ws.merge_cells('J17:J20')
ws.column_dimensions.group('A','D', hidden=True)
ws.row_dimensions.group(1,10, hidden=True)
wb.save(dest_filename)
#ws.unmerge_cells('A2:D2')

@ -224,12 +224,13 @@ class FundQuery:
c_class_result = self.cursor.fetchone()
return c_class_result
#获取基金十大持仓以及代码,名称
def select_top_10_stock(self, quarter_index=None, fund_code_pool=None):
stock_sql_join = ''
for index in range(10):
stock_sql_join = stock_sql_join + \
"t.top_stock_%s_code, t.top_stock_%s_name" % (
str(index), str(index)) + ","
"t.top_stock_%s_code, t.top_stock_%s_name, t.top_stock_%s_portion" % (
str(index), str(index), str(index)) + ","
stock_sql_join = stock_sql_join[0:-1]
fund_code_list_sql = ''
# 判断是否传入fund_code_pool
@ -238,7 +239,7 @@ class FundQuery:
return ()
list_str = ', '.join(fund_code_pool)
fund_code_list_sql = "AND t.fund_code IN (" + list_str + ")"
sql_query_quarter = "SELECT t.fund_code," + stock_sql_join + \
sql_query_quarter = "SELECT t.fund_code, t.fund_name, t.stock_position_total, " + stock_sql_join + \
" FROM fund_morning_stock_info as t WHERE t.quarter_index = %s AND t.stock_position_total > 20 " + \
fund_code_list_sql + \
";" # 大于20%股票持仓基金
@ -249,13 +250,13 @@ class FundQuery:
return results
# 分组查询特定股票的每个季度基金持有总数
def select_special_stock_fund_count(self, stock_name, fund_code_pool=None):
def select_special_stock_fund_count(self, stock_code, fund_code_pool=None):
stock_sql_join = '('
for index in range(10):
escape_name = stock_name.replace("'", "\\'")
escape_code = stock_code.replace("'", "\\'")
stock_sql_join = stock_sql_join + \
"t.top_stock_{0}_name = '{1}' or ".format(
str(index), escape_name)
"t.top_stock_{0}_code = '{1}' or ".format(
str(index), escape_code)
stock_sql_join = stock_sql_join[0:-3] + ')'
fund_code_list_sql = ''
# 判断是否传入fund_code_pool

@ -62,8 +62,8 @@ def get_quarter_index(input_date):
return index
def get_last_quarter_str():
last_quarter_time = time.localtime(time.time() - 3 * 30 * 24 * 3600)
def get_last_quarter_str(last_index=1):
last_quarter_time = time.localtime(time.time() - last_index * 3 * 30 * 24 * 3600)
year = time.strftime("%Y", last_quarter_time)
date = time.strftime("%m-%d", last_quarter_time)
index = get_quarter_index(date)
@ -75,3 +75,10 @@ def get_quarter_date(quarter_index_str):
boundary_date_list = ['03-31', '06-30', '09-30', '12-31']
quarter_index = quarter_index_str.split('-')[1][1:]
return year + '-' + boundary_date_list[int(quarter_index) - 1]
def fisrt_match_condition_from_list(list, code):
for item in list:
stock_code = item.split('-', 1)[0]
is_exist = code == stock_code
if is_exist:
return item

Loading…
Cancel
Save