699 lines
26 KiB
Plaintext
699 lines
26 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "code",
|
||
"id": "initial_id",
|
||
"metadata": {
|
||
"collapsed": true,
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:32.313699Z",
|
||
"start_time": "2025-01-20T09:12:32.310753Z"
|
||
}
|
||
},
|
||
"source": [
|
||
"\n",
|
||
"import pandas as pd\n",
|
||
"import tushare as ts\n",
|
||
"\n",
|
||
"ts_pro = ts.pro_api(token=\"64ebff4fa679167600b905ee45dd88e76f3963c0ff39157f3f085f0e\")"
|
||
],
|
||
"outputs": [],
|
||
"execution_count": 99
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:35.800981Z",
|
||
"start_time": "2025-01-20T09:12:32.319361Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"import loader as loader\n",
|
||
"\n",
|
||
"# 加载财报信息\n",
|
||
"source_finance_df = loader.load_finance()\n",
|
||
"finance_df = pd.DataFrame()\n",
|
||
"finance_df[[\n",
|
||
" \"code\",\n",
|
||
" # 年份\n",
|
||
" \"year\",\n",
|
||
" # 股东权益合计(含少数股东权益)\n",
|
||
" \"total_stockholder_interest\",\n",
|
||
" # 净利润\n",
|
||
" \"net_income\",\n",
|
||
" # 总资产\n",
|
||
" \"total_assets\",\n",
|
||
" # 营业总收入\n",
|
||
" \"total_revenue\",\n",
|
||
" # 存货\n",
|
||
" \"inventories\",\n",
|
||
" # 应收账款\n",
|
||
" \"accounts_receivable\",\n",
|
||
" # 营业成本\n",
|
||
" \"operating_costs\",\n",
|
||
" # 营业利润\n",
|
||
" \"operating_profit\",\n",
|
||
" # 现金与现金等价物\n",
|
||
" \"cash\",\n",
|
||
" # 营业活动现金流量净值\n",
|
||
" \"operating_net_cash_flow\",\n",
|
||
"]] = source_finance_df[[\n",
|
||
" \"ts_code\",\n",
|
||
" \"end_date\",\n",
|
||
" \"total_hldr_eqy_inc_min_int\",\n",
|
||
" \"n_income\",\n",
|
||
" \"total_assets\",\n",
|
||
" \"total_revenue\",\n",
|
||
" \"inventories\",\n",
|
||
" \"accounts_receiv\",\n",
|
||
" \"oper_cost\",\n",
|
||
" \"operate_profit\",\n",
|
||
" \"money_cap\",\n",
|
||
" \"n_cashflow_act\",\n",
|
||
"]]\n",
|
||
"finance_df[\"score\"] = 0\n",
|
||
"finance_df = finance_df.sort_values(by=[\"code\", \"year\"], ascending=True).reset_index(drop=True)"
|
||
],
|
||
"id": "68b2debc14502fd5",
|
||
"outputs": [],
|
||
"execution_count": 100
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": "过滤上市时间大于5年的企业,由于计算很多数值需要与前一年比,所以实际上需要的是上市时间至少6年的企业",
|
||
"id": "3052b8c4442f3643"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:35.994681Z",
|
||
"start_time": "2025-01-20T09:12:35.828990Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": "finance_df = finance_df.groupby(\"code\").filter(lambda x: len(x) > 6)",
|
||
"id": "4293bd93ea8f9ed",
|
||
"outputs": [],
|
||
"execution_count": 101
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"ROE\n",
|
||
"\n",
|
||
"股东权益报酬率(%) RoE\t股东权益报酬率RoE 是判断股票是否具备”长期上涨潜力“最重要的指标之一, RoE 如果既稳定又优秀,那这家公司的其他指标也基本不会差。 \n",
|
||
"RoE均值 >= 35\t550分 \n",
|
||
"35 > RoE均值 >= 30\t500分 \n",
|
||
"30 > RoE均值 >= 25\t450分 \n",
|
||
"25 > RoE均值 >= 20\t400分 \n",
|
||
"20 > RoE均值 >= 15\t300分 \n",
|
||
"15 > RoE均值 >= 10\t250分 \n",
|
||
"10 > RoE均值 或 0 >= 其中一年\t0分 "
|
||
],
|
||
"id": "336aa970ee46709d"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:38.908153Z",
|
||
"start_time": "2025-01-20T09:12:36.022143Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"finance_df[\"prev_total_stockholder_interest\"] = finance_df.groupby(\"code\")[\"total_stockholder_interest\"].shift(1)\n",
|
||
"finance_df[\"roe\"] = finance_df[\"net_income\"] / (\n",
|
||
" (finance_df[\"prev_total_stockholder_interest\"] + finance_df[\"total_stockholder_interest\"]) / 2)\n",
|
||
"finance_df[\"average_roe\"] = finance_df.groupby(\"code\")[\"roe\"].rolling(window=5).mean().reset_index(0, drop=True)\n",
|
||
"finance_df[\"score_roe\"] = 0\n",
|
||
"finance_df.loc[finance_df[\"average_roe\"] >= 0.35, \"score_roe\"] += 550\n",
|
||
"finance_df.loc[(finance_df[\"average_roe\"] >= 0.30) & (finance_df[\"average_roe\"] < 0.35), \"score_roe\"] = 500\n",
|
||
"finance_df.loc[(finance_df[\"average_roe\"] >= 0.25) & (finance_df[\"average_roe\"] < 0.30), \"score_roe\"] = 450\n",
|
||
"finance_df.loc[(finance_df[\"average_roe\"] >= 0.20) & (finance_df[\"average_roe\"] < 0.25), \"score_roe\"] = 400\n",
|
||
"finance_df.loc[(finance_df[\"average_roe\"] >= 0.15) & (finance_df[\"average_roe\"] < 0.20), \"score_roe\"] = 300\n",
|
||
"finance_df.loc[(finance_df[\"average_roe\"] >= 0.10) & (finance_df[\"average_roe\"] < 0.15), \"score_roe\"] = 250\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_roe\"]\n",
|
||
"\n",
|
||
"\n",
|
||
"def reset_score_for_average_roe(group):\n",
|
||
" group.loc[group['average_roe'].rolling(window=5, min_periods=1).min() < 0, 'score'] = 0\n",
|
||
" return group\n",
|
||
"\n",
|
||
"\n",
|
||
"finance_df = finance_df.groupby(\"code\").apply(reset_score_for_average_roe).reset_index(drop=True)"
|
||
],
|
||
"id": "f050d33c4a0cd720",
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_72996/1604170078.py:20: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
|
||
" finance_df = finance_df.groupby(\"code\").apply(reset_score_for_average_roe).reset_index(drop=True)\n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 102
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"总资产报酬率(%) RoA\t总资产报酬率RoA 能真实反映出一家公司的获利能力, 相当于一家公司的 「投资年化率」,当然越高越好。\n",
|
||
"RoA均值 >= 15\t100分\n",
|
||
"15 > RoA均值 >= 11\t80分\n",
|
||
"11 > RoA均值 >= 7\t50分\n",
|
||
"7 > RoA均值\t0分"
|
||
],
|
||
"id": "6c2e1c602898e342"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:39.103417Z",
|
||
"start_time": "2025-01-20T09:12:38.937447Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"finance_df[\"prev_total_assets\"] = finance_df.groupby(\"code\")[\"total_assets\"].shift(1)\n",
|
||
"finance_df[\"roa\"] = finance_df[\"net_income\"] / ((finance_df[\"prev_total_assets\"] + finance_df[\"total_assets\"]) / 2)\n",
|
||
"finance_df[\"average_roa\"] = finance_df.groupby(\"code\")[\"roa\"].rolling(window=5).mean().reset_index(0, drop=True)\n",
|
||
"finance_df[\"score_roa\"] = 0\n",
|
||
"finance_df.loc[finance_df[\"average_roa\"] >= 0.15, \"score_roa\"] += 100\n",
|
||
"finance_df.loc[(finance_df[\"average_roa\"] >= 0.11) & (finance_df[\"average_roa\"] < 0.15), \"score_roa\"] += 80\n",
|
||
"finance_df.loc[(finance_df[\"average_roa\"] >= 0.07) & (finance_df[\"average_roa\"] < 0.11), \"score_roa\"] += 50\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_roa\"]"
|
||
],
|
||
"id": "3b585cf8e2eb5e3",
|
||
"outputs": [],
|
||
"execution_count": 103
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"税后净利 规模(百万)\t获利规模大,那股价的”长期上涨潜力“也就会越稳健、越确定。选择时,大公司的优先级要高于小公司。\n",
|
||
"税后净利均值 >= 10000\t150分\n",
|
||
"10000 > 税后净利均值 >= 1000\t100分\n",
|
||
"1000 > 税后净利均值\t0分"
|
||
],
|
||
"id": "dbcb1d6b23582f3e"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:39.922683Z",
|
||
"start_time": "2025-01-20T09:12:39.130104Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"finance_df['average_net_income'] = finance_df.groupby('code')['net_income'].transform(lambda x: x.rolling(5).mean())\n",
|
||
"finance_df[\"score_net_income\"] = 0\n",
|
||
"finance_df.loc[finance_df[\"average_net_income\"] >= 10000 * 10000000, \"score_net_income\"] = 150\n",
|
||
"finance_df.loc[(finance_df[\"average_net_income\"] >= 1000 * 10000000) & (\n",
|
||
" finance_df[\"average_net_income\"] < 10000 * 10000000), \"score_net_income\"] = 100\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_net_income\"]"
|
||
],
|
||
"id": "fd5582e080102e20",
|
||
"outputs": [],
|
||
"execution_count": 104
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"现金状况 分析\t总资产周转率 与 现金与约当现金占总资产的关系,可以看出公司的现金状况是否健康。\n",
|
||
"规则①:总资产周转率 > 0.8 且 现金与约当现金占总资产(%) >= 10\t50分\n",
|
||
"规则②:总资产周转率 < 0.8 且 现金与约当现金占总资产(%) >= 20\t50分\n",
|
||
"不符合 规则① 或 规则②\t0分"
|
||
],
|
||
"id": "2c6c934a376eef0d"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:39.965030Z",
|
||
"start_time": "2025-01-20T09:12:39.946246Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"finance_df[\"prev_total_assets\"] = finance_df.groupby(\"code\")[\"total_assets\"].shift(1)\n",
|
||
"finance_df[\"total_assets_turnover_ratio\"] = finance_df[\"total_revenue\"] / (\n",
|
||
" (finance_df[\"prev_total_assets\"] + finance_df[\"total_assets\"]) / 2)\n",
|
||
"\n",
|
||
"finance_df[\"cash_ratio\"] = finance_df[\"cash\"] / finance_df[\"total_assets\"]\n",
|
||
"\n",
|
||
"finance_df[\"score_assets_turnover_and_cash\"] = 0\n",
|
||
"finance_df.loc[(finance_df[\"total_assets_turnover_ratio\"] >= 0.8) & (\n",
|
||
" finance_df[\"cash_ratio\"] >= 0.1), \"score_assets_turnover_and_cash\"] = 50\n",
|
||
"finance_df.loc[(finance_df[\"total_assets_turnover_ratio\"] < 0.8) & (\n",
|
||
" finance_df[\"cash_ratio\"] >= 0.2), \"score_assets_turnover_and_cash\"] = 50\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_assets_turnover_and_cash\"]"
|
||
],
|
||
"id": "bc92e050c82c3768",
|
||
"outputs": [],
|
||
"execution_count": 105
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"收现日数(日)\t平均收现日数越短,说明公司的经营能力越强。\n",
|
||
"30 >= 平均收现日数\t20分\n",
|
||
"平均收现日数 > 30\t0分\n",
|
||
"\n",
|
||
"销货日数(日)\t平均销货日数越短,说明公司商品越畅销。\n",
|
||
"30 >= 平均销货日数\t20分\n",
|
||
"平均销货日数 > 30\t0分\n",
|
||
"\n",
|
||
"收现日数+销货日数(日)\t生意周期 是否足够优秀,越短说明每年能做的生意趟数越多,经营能力就越强。\n",
|
||
"40 >= 收现日数+销货日数\t20分\n",
|
||
"60 >= 收现日数+销货日数 > 40\t10分\n",
|
||
"平均销货日数 > 60\t0分"
|
||
],
|
||
"id": "41ac526b0296b44b"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:40.003327Z",
|
||
"start_time": "2025-01-20T09:12:39.990482Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"# 收现日数\n",
|
||
"finance_df[\"collection_cash_period\"] = 360 / (finance_df[\"total_revenue\"] / finance_df[\"accounts_receivable\"])\n",
|
||
"# 销货日数\n",
|
||
"finance_df[\"sales_period\"] = 360 / (finance_df[\"operating_costs\"] / finance_df[\"accounts_receivable\"])\n",
|
||
"\n",
|
||
"finance_df[\"score_collection_cash_period\"] = 0\n",
|
||
"finance_df.loc[(not finance_df[\"score_collection_cash_period\"].isna) & (\n",
|
||
" finance_df[\"collection_cash_period\"] < 30), \"score_collection_cash_period\"] = 20\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_collection_cash_period\"]\n",
|
||
"\n",
|
||
"finance_df[\"score_sales_period\"] = 0\n",
|
||
"finance_df.loc[\n",
|
||
" (not finance_df[\"score_sales_period\"].isna) & (finance_df[\"score_sales_period\"] < 30), \"score_sales_period\"] = 20\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_sales_period\"]\n",
|
||
"\n",
|
||
"finance_df[\"score_collection_cash_period_and_sales_period\"] = 0\n",
|
||
"finance_df.loc[(finance_df[\"collection_cash_period\"] + finance_df[\n",
|
||
" \"sales_period\"]) < 40, \"score_collection_cash_period_and_sales_period\"] = 20\n",
|
||
"finance_df.loc[(finance_df[\"collection_cash_period\"] + finance_df[\n",
|
||
" \"sales_period\"]) < 60, \"score_collection_cash_period_and_sales_period\"] = 10\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_collection_cash_period_and_sales_period\"]"
|
||
],
|
||
"id": "baeb44a4fb28b60b",
|
||
"outputs": [],
|
||
"execution_count": 106
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"毛利率(%)\t毛利率 是否保持平稳,不大起大落。\n",
|
||
"30% >= 毛利率平均波动幅度\t50分\n",
|
||
"毛利率平均波动幅度 > 30%\t0分"
|
||
],
|
||
"id": "a53bfdb799df8f48"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:40.179998Z",
|
||
"start_time": "2025-01-20T09:12:40.027705Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"finance_df[\"gross_profit_ratio\"] = (finance_df[\"total_revenue\"] - finance_df[\"operating_costs\"]) / finance_df[\n",
|
||
" \"total_revenue\"]\n",
|
||
"finance_df[\"gross_profit_ratio_std\"] = finance_df.groupby(\"code\")[\"gross_profit_ratio\"].rolling(\n",
|
||
" window=5\n",
|
||
").std().reset_index(0, drop=True)\n",
|
||
"finance_df[\"score_gross_profit_ratio\"] = 0\n",
|
||
"finance_df[(not finance_df[\"gross_profit_ratio_std\"].isna) & (finance_df[\"gross_profit_ratio_std\"] < 30)] = 50\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_gross_profit_ratio\"]"
|
||
],
|
||
"id": "9d23bdf60a1839c9",
|
||
"outputs": [],
|
||
"execution_count": 107
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"经营安全边际率(%)\t经营安全边际率越高,说明公司能够很好的控制成本,把大部分利润转化成实际收益, 获利能力很强,有利于抵御经济波动和价格竞争等影响。\n",
|
||
"经营安全边际率 >= 70\t50分\n",
|
||
"70 > 经营安全边际率 >= 50\t30分\n",
|
||
"50 > 经营安全边际率 >= 30\t10分\n",
|
||
"30 > 经营安全边际率\t0分"
|
||
],
|
||
"id": "6613ab8263d4afef"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:40.213136Z",
|
||
"start_time": "2025-01-20T09:12:40.205548Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"finance_df[\"operating_profit_ratio\"] = finance_df[\"operating_profit\"] / finance_df[\"total_revenue\"]\n",
|
||
"finance_df[\"operating_safety_margin\"] = finance_df[\"operating_profit_ratio\"] / finance_df[\"gross_profit_ratio\"]\n",
|
||
"finance_df[\"score_operating_safety_margin\"] = 0\n",
|
||
"finance_df.loc[finance_df[\"operating_safety_margin\"] >= 70, \"score_operating_safety_margin\"] = 50\n",
|
||
"finance_df.loc[finance_df[\"operating_safety_margin\"] >= 50, \"score_operating_safety_margin\"] = 30\n",
|
||
"finance_df.loc[finance_df[\"operating_safety_margin\"] >= 30, \"score_operating_safety_margin\"] = 10\n",
|
||
"finance_df[\"score\"] += finance_df[\"score_operating_safety_margin\"]"
|
||
],
|
||
"id": "f7d9486af89cb710",
|
||
"outputs": [],
|
||
"execution_count": 108
|
||
},
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "markdown",
|
||
"source": [
|
||
"税后净利\n",
|
||
"年份由近(A)~远(E)\t公司赚的钱是否在逐年增长,是股价能长期上涨的基础。\n",
|
||
"A年 > B年 (+) / A年 < B年 (-)\t+30分 / -30分\n",
|
||
"B年 > C年 (+) / B年 < C年 (-)\t+25分 / -25分\n",
|
||
"C年 > D年 (+) / C年 < D年 (-)\t+20分 / -20分\n",
|
||
"D年 > E年 (+) / D年 < E年 (-)\t+15分 / -15分"
|
||
],
|
||
"id": "2ee3712525455954"
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:12:57.833029Z",
|
||
"start_time": "2025-01-20T09:12:40.241875Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"def score_by_net_income_ascending(group):\n",
|
||
" # 计算 score_net_income_1\n",
|
||
" group['net_income_shift_1'] = group['net_income'].shift(1)\n",
|
||
" group['score_net_income_1'] = (group['net_income'] > group['net_income_shift_1']).map(\n",
|
||
" {True: 30, False: -30}\n",
|
||
" )\n",
|
||
" # 计算 score_net_income_2\n",
|
||
" group['net_income_shift_2'] = group['net_income'].shift(2)\n",
|
||
" group['score_net_income_2'] = (group['net_income_shift_1'] > group['net_income_shift_2']).map(\n",
|
||
" {True: 25, False: -25}\n",
|
||
" )\n",
|
||
" # 计算 score_net_income_3\n",
|
||
" group['net_income_shift_3'] = group['net_income'].shift(3)\n",
|
||
" group['score_net_income_3'] = (group['net_income_shift_2'] > group['net_income_shift_3']).map(\n",
|
||
" {True: 20, False: -20}\n",
|
||
" )\n",
|
||
" # 计算 score_net_income_4\n",
|
||
" group['net_income_shift_4'] = group['net_income'].shift(4)\n",
|
||
" group['score_net_income_4'] = (group['net_income_shift_3'] > group['net_income_shift_4']).map(\n",
|
||
" {True: 15, False: -15}\n",
|
||
" )\n",
|
||
" return group\n",
|
||
"\n",
|
||
"\n",
|
||
"finance_df = finance_df.groupby(\"code\").apply(score_by_net_income_ascending).reset_index(drop=True)\n",
|
||
"finance_df[\"score_net_income_ascending\"] = finance_df[\"score_net_income_1\"] + finance_df[\"score_net_income_2\"] + \\\n",
|
||
" finance_df[\"score_net_income_3\"] + finance_df[\"score_net_income_4\"]"
|
||
],
|
||
"id": "2d1ca7fc7873ce71",
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_72996/432379325.py:25: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
|
||
" finance_df = finance_df.groupby(\"code\").apply(score_by_net_income_ascending).reset_index(drop=True)\n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 109
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:13:15.433529Z",
|
||
"start_time": "2025-01-20T09:12:57.864097Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"def score_by_operating_net_cash_flow_ascending(group):\n",
|
||
" # 计算 score_operating_net_cash_flow_1\n",
|
||
" group['operating_net_cash_flow_shift_1'] = group['operating_net_cash_flow'].shift(1)\n",
|
||
" group['score_operating_net_cash_flow_1'] = (\n",
|
||
" group['operating_net_cash_flow'] > group['operating_net_cash_flow_shift_1']).map(\n",
|
||
" {True: 30, False: -30}\n",
|
||
" )\n",
|
||
" # 计算 score_operating_net_cash_flow_2\n",
|
||
" group['operating_net_cash_flow_shift_2'] = group['operating_net_cash_flow'].shift(2)\n",
|
||
" group['score_operating_net_cash_flow_2'] = (\n",
|
||
" group['operating_net_cash_flow_shift_1'] > group['operating_net_cash_flow_shift_2']).map(\n",
|
||
" {True: 25, False: -25}\n",
|
||
" )\n",
|
||
" # 计算 score_operating_net_cash_flow_3\n",
|
||
" group['operating_net_cash_flow_shift_3'] = group['operating_net_cash_flow'].shift(3)\n",
|
||
" group['score_operating_net_cash_flow_3'] = (\n",
|
||
" group['operating_net_cash_flow_shift_2'] > group['operating_net_cash_flow_shift_3']).map(\n",
|
||
" {True: 20, False: -20}\n",
|
||
" )\n",
|
||
" # 计算 score_operating_net_cash_flow_4\n",
|
||
" group['operating_net_cash_flow_shift_4'] = group['operating_net_cash_flow'].shift(4)\n",
|
||
" group['score_operating_net_cash_flow_4'] = (\n",
|
||
" group['operating_net_cash_flow_shift_3'] > group['operating_net_cash_flow_shift_4']).map(\n",
|
||
" {True: 15, False: -15}\n",
|
||
" )\n",
|
||
" return group\n",
|
||
"\n",
|
||
"\n",
|
||
"finance_df = finance_df.groupby(\"code\").apply(score_by_operating_net_cash_flow_ascending).reset_index(drop=True)\n",
|
||
"finance_df[\"score_operating_net_cash_flow_ascending\"] = finance_df[\"score_operating_net_cash_flow_1\"] + finance_df[\n",
|
||
" \"score_operating_net_cash_flow_2\"] + finance_df[\"score_operating_net_cash_flow_3\"] + finance_df[\n",
|
||
" \"score_operating_net_cash_flow_4\"]"
|
||
],
|
||
"id": "a90f3721487bd635",
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_72996/2138932640.py:29: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
|
||
" finance_df = finance_df.groupby(\"code\").apply(score_by_operating_net_cash_flow_ascending).reset_index(drop=True)\n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 110
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-01-20T09:15:08.342704Z",
|
||
"start_time": "2025-01-20T09:15:08.302792Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"result_df = finance_df.sort_values(by=['score'], ascending=False, inplace=False)[[\"code\", \"score\"]]\n",
|
||
"result_df = result_df.drop_duplicates(\"code\")\n",
|
||
"result_df[:20]"
|
||
],
|
||
"id": "ef9e6259efc1c1d0",
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
" code score\n",
|
||
"48060 600519.SH 810\n",
|
||
"45062 600309.SH 810\n",
|
||
"58715 601919.SH 790\n",
|
||
"17006 002415.SZ 750\n",
|
||
"3252 000587.SZ 710\n",
|
||
"4129 000651.SZ 710\n",
|
||
"64547 603868.SH 710\n",
|
||
"56747 601225.SH 710\n",
|
||
"4457 000672.SZ 710\n",
|
||
"3031 000568.SZ 710\n",
|
||
"8872 001201.SZ 710\n",
|
||
"31827 300390.SZ 710\n",
|
||
"65769 605098.SH 710\n",
|
||
"46474 600398.SH 710\n",
|
||
"65749 605089.SH 710\n",
|
||
"64240 603816.SH 710\n",
|
||
"47860 600507.SH 710\n",
|
||
"33696 300533.SZ 710\n",
|
||
"27948 300146.SZ 710\n",
|
||
"35448 300677.SZ 710"
|
||
],
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>code</th>\n",
|
||
" <th>score</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>48060</th>\n",
|
||
" <td>600519.SH</td>\n",
|
||
" <td>810</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>45062</th>\n",
|
||
" <td>600309.SH</td>\n",
|
||
" <td>810</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>58715</th>\n",
|
||
" <td>601919.SH</td>\n",
|
||
" <td>790</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>17006</th>\n",
|
||
" <td>002415.SZ</td>\n",
|
||
" <td>750</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3252</th>\n",
|
||
" <td>000587.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4129</th>\n",
|
||
" <td>000651.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>64547</th>\n",
|
||
" <td>603868.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>56747</th>\n",
|
||
" <td>601225.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4457</th>\n",
|
||
" <td>000672.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3031</th>\n",
|
||
" <td>000568.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8872</th>\n",
|
||
" <td>001201.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>31827</th>\n",
|
||
" <td>300390.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>65769</th>\n",
|
||
" <td>605098.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>46474</th>\n",
|
||
" <td>600398.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>65749</th>\n",
|
||
" <td>605089.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>64240</th>\n",
|
||
" <td>603816.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>47860</th>\n",
|
||
" <td>600507.SH</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>33696</th>\n",
|
||
" <td>300533.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>27948</th>\n",
|
||
" <td>300146.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>35448</th>\n",
|
||
" <td>300677.SZ</td>\n",
|
||
" <td>710</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>"
|
||
]
|
||
},
|
||
"execution_count": 114,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"execution_count": 114
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 2
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython2",
|
||
"version": "2.7.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|