diff --git a/poetry.lock b/poetry.lock
index 6e9be89..0392c3f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -3321,14 +3321,14 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,
[[package]]
name = "tushare"
-version = "1.4.16"
+version = "1.4.17"
description = "A utility for crawling historical and Real-time Quotes data of China stocks"
optional = false
python-versions = "*"
groups = ["main"]
files = [
- {file = "tushare-1.4.16-py3-none-any.whl", hash = "sha256:43ae9bd0a356b8eb16a781b096c4ba849eb6ff7854c9fce8aadc01e0a487e196"},
- {file = "tushare-1.4.16.tar.gz", hash = "sha256:20b6b9a1841bf730da3c27e68aa08a4fe4c4636a7fe6308903b46c9622d4467c"},
+ {file = "tushare-1.4.17-py3-none-any.whl", hash = "sha256:a367389cbc50098f49a397263284ec424877b72e4776cb2ba59d4b0dd6f2bc37"},
+ {file = "tushare-1.4.17.tar.gz", hash = "sha256:e73c471ec96261b70937a66daa7942ad6372a86a37218468980c61dc8bace323"},
]
[package.dependencies]
diff --git a/财报筛选/loader.py b/财报筛选/loader.py
index 1853cf5..5953ea1 100644
--- a/财报筛选/loader.py
+++ b/财报筛选/loader.py
@@ -2,7 +2,8 @@ import os.path
import pandas as pd
-finance_root = "/Users/lanyuanxiaoyao/SynologyDrive/data/Tushare"
+# finance_root = "/Users/lanyuanxiaoyao/SynologyDrive/data/Tushare"
+finance_root = "C:\\Users\\lanyuanxiaoyao\\Documents\\Tushare"
def load_balance_sheet():
diff --git a/财报筛选/金字塔选股.ipynb b/财报筛选/金字塔选股.ipynb
index 0bd1be2..bbcd4a4 100644
--- a/财报筛选/金字塔选股.ipynb
+++ b/财报筛选/金字塔选股.ipynb
@@ -6,127 +6,31 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-01-17T02:07:55.001963Z",
- "start_time": "2025-01-17T02:07:54.772694Z"
+ "end_time": "2025-01-19T16:42:26.631868Z",
+ "start_time": "2025-01-19T16:42:26.628635Z"
}
},
"source": [
+ "import numpy as np\n",
"import pandas as pd\n",
"import tushare as ts\n",
"\n",
"ts_pro = ts.pro_api(token=\"64ebff4fa679167600b905ee45dd88e76f3963c0ff39157f3f085f0e\")"
],
"outputs": [],
- "execution_count": 2
+ "execution_count": 459
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-01-17T08:18:12.685428Z",
- "start_time": "2025-01-17T08:18:12.676949Z"
- }
- },
- "cell_type": "code",
- "source": [
- "df = pd.DataFrame([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]])\n",
- "df.loc[df[0] > 2, 2] += 100\n",
- "df"
- ],
- "id": "e19fd115ed8cb631",
- "outputs": [
- {
- "data": {
- "text/plain": [
- " 0 1 2 3 4\n",
- "0 1 2 3 4 5\n",
- "1 6 7 108 9 10\n",
- "2 11 12 113 14 15\n",
- "3 16 17 118 19 20"
- ],
- "text/html": [
- "
\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " 0 | \n",
- " 1 | \n",
- " 2 | \n",
- " 3 | \n",
- " 4 | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " | 0 | \n",
- " 1 | \n",
- " 2 | \n",
- " 3 | \n",
- " 4 | \n",
- " 5 | \n",
- "
\n",
- " \n",
- " | 1 | \n",
- " 6 | \n",
- " 7 | \n",
- " 108 | \n",
- " 9 | \n",
- " 10 | \n",
- "
\n",
- " \n",
- " | 2 | \n",
- " 11 | \n",
- " 12 | \n",
- " 113 | \n",
- " 14 | \n",
- " 15 | \n",
- "
\n",
- " \n",
- " | 3 | \n",
- " 16 | \n",
- " 17 | \n",
- " 118 | \n",
- " 19 | \n",
- " 20 | \n",
- "
\n",
- " \n",
- "
\n",
- "
"
- ]
- },
- "execution_count": 86,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 86
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-17T10:11:56.563929Z",
- "start_time": "2025-01-17T10:11:52.872684Z"
+ "end_time": "2025-01-19T16:42:27.857016Z",
+ "start_time": "2025-01-19T16:42:26.639161Z"
}
},
"cell_type": "code",
"source": [
"import loader as loader\n",
"\n",
- "# 加载股票信息\n",
- "stock_df = pd.read_csv(\"../材料/股票基础信息.csv\")\n",
"# 加载财报信息\n",
"source_finance_df = loader.load_finance()\n",
"finance_df = pd.DataFrame()\n",
@@ -169,11 +73,11 @@
" \"n_cashflow_act\",\n",
"]]\n",
"finance_df[\"score\"] = 0\n",
- "finance_df = finance_df.sort_values(by=[\"code\", \"year\"], ascending=True)"
+ "finance_df = finance_df.sort_values(by=[\"code\", \"year\"], ascending=True).reset_index(drop=True)"
],
"id": "68b2debc14502fd5",
"outputs": [],
- "execution_count": 148
+ "execution_count": 460
},
{
"metadata": {},
@@ -184,15 +88,15 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-01-17T10:11:57.531470Z",
- "start_time": "2025-01-17T10:11:57.287352Z"
+ "end_time": "2025-01-19T16:42:27.931899Z",
+ "start_time": "2025-01-19T16:42:27.868963Z"
}
},
"cell_type": "code",
"source": "finance_df = finance_df.groupby(\"code\").filter(lambda x: len(x) > 6)",
"id": "4293bd93ea8f9ed",
"outputs": [],
- "execution_count": 149
+ "execution_count": 461
},
{
"metadata": {},
@@ -214,8 +118,8 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-01-17T10:12:05.859920Z",
- "start_time": "2025-01-17T10:12:00.853021Z"
+ "end_time": "2025-01-19T16:42:29.192712Z",
+ "start_time": "2025-01-19T16:42:27.946033Z"
}
},
"cell_type": "code",
@@ -224,17 +128,22 @@
"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.loc[finance_df[\"average_roe\"] >= 0.35, \"score\"] += 550\n",
- "finance_df.loc[(finance_df[\"average_roe\"] >= 0.30) & (finance_df[\"average_roe\"] < 0.35), \"score\"] += 500\n",
- "finance_df.loc[(finance_df[\"average_roe\"] >= 0.25) & (finance_df[\"average_roe\"] < 0.30), \"score\"] += 450\n",
- "finance_df.loc[(finance_df[\"average_roe\"] >= 0.20) & (finance_df[\"average_roe\"] < 0.25), \"score\"] += 400\n",
- "finance_df.loc[(finance_df[\"average_roe\"] >= 0.15) & (finance_df[\"average_roe\"] < 0.20), \"score\"] += 300\n",
- "finance_df.loc[(finance_df[\"average_roe\"] >= 0.10) & (finance_df[\"average_roe\"] < 0.15), \"score\"] += 250\n",
- "finance_df[\"score\"] = finance_df.groupby(\"code\").apply(\n",
- " lambda x: x[\"score\"].mask(x[\"average_roe\"].rolling(window=5).apply(lambda y: (y < 0).any(), raw=False) > 0, 0)\n",
- ").reset_index(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",
- "finance_df[finance_df[\"code\"] == '000002.SZ']"
+ "\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": [
@@ -242,117 +151,374 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_54636/2126828454.py:12: 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[\"score\"] = finance_df.groupby(\"code\").apply(\n"
+ "C:\\Users\\lanyuanxiaoyao\\AppData\\Local\\Temp\\ipykernel_28824\\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": 462
+ },
+ {
+ "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-19T16:42:29.363249Z",
+ "start_time": "2025-01-19T16:42:29.219453Z"
+ }
+ },
+ "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": 463
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": [
+ "税后净利 规模(百万)\t获利规模大,那股价的”长期上涨潜力“也就会越稳健、越确定。选择时,大公司的优先级要高于小公司。\n",
+ "税后净利均值 >= 10000\t150分\n",
+ "10000 > 税后净利均值 >= 1000\t100分\n",
+ "1000 > 税后净利均值\t0分"
+ ],
+ "id": "dbcb1d6b23582f3e"
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-01-19T16:42:29.878285Z",
+ "start_time": "2025-01-19T16:42:29.369862Z"
+ }
+ },
+ "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": 464
+ },
+ {
+ "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-19T16:42:29.905727Z",
+ "start_time": "2025-01-19T16:42:29.889468Z"
+ }
+ },
+ "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": 465
+ },
+ {
+ "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-19T16:42:29.923829Z",
+ "start_time": "2025-01-19T16:42:29.916781Z"
+ }
+ },
+ "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": 466
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": [
+ "毛利率(%)\t毛利率 是否保持平稳,不大起大落。\n",
+ "30% >= 毛利率平均波动幅度\t50分\n",
+ "毛利率平均波动幅度 > 30%\t0分"
+ ],
+ "id": "a53bfdb799df8f48"
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-01-19T16:42:30.005541Z",
+ "start_time": "2025-01-19T16:42:29.935348Z"
+ }
+ },
+ "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).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": 467
+ },
+ {
+ "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-19T16:42:30.022774Z",
+ "start_time": "2025-01-19T16:42:30.016550Z"
+ }
+ },
+ "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": 468
+ },
+ {
+ "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-19T16:42:46.378919Z",
+ "start_time": "2025-01-19T16:42:30.718209Z"
+ }
+ },
+ "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",
+ " group = group.mask(pd.isna(group[\"net_income_shift_1\"]), other=0)\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",
+ " # 计算 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",
+ " # 计算 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}).fillna(0)\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\"] = np.sum(\n",
+ " [finance_df[\"score_net_income_1\"], finance_df[\"score_net_income_2\"], finance_df[\"score_net_income_3\"],\n",
+ " finance_df[\"score_net_income_4\"]], axis=0)\n",
+ "finance_df"
+ ],
+ "id": "2d1ca7fc7873ce71",
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\lanyuanxiaoyao\\AppData\\Local\\Temp\\ipykernel_28824\\3206398043.py:22: 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"
]
},
{
"data": {
"text/plain": [
" code year total_stockholder_interest net_income \\\n",
- "1945 000002.SZ 2005 8.581223e+09 1.433426e+09 \n",
- "3432 000002.SZ 2006 1.745350e+10 2.422997e+09 \n",
- "5449 000002.SZ 2007 3.391952e+10 5.317501e+09 \n",
- "7921 000002.SZ 2008 3.881855e+10 4.639869e+09 \n",
- "10605 000002.SZ 2009 4.540851e+10 6.430008e+09 \n",
- "13934 000002.SZ 2010 5.458620e+10 8.839611e+09 \n",
- "17289 000002.SZ 2011 6.783254e+10 1.159961e+10 \n",
- "20376 000002.SZ 2012 8.213819e+10 1.566259e+10 \n",
- "25215 000002.SZ 2013 1.054394e+11 1.829755e+10 \n",
- "29387 000002.SZ 2014 1.158936e+11 1.928752e+10 \n",
- "33753 000002.SZ 2015 1.363096e+11 2.594944e+10 \n",
- "37463 000002.SZ 2016 1.616766e+11 2.835026e+10 \n",
- "42678 000002.SZ 2017 1.866739e+11 3.720839e+10 \n",
- "47756 000002.SZ 2018 2.356207e+11 4.927229e+10 \n",
- "52944 000002.SZ 2019 2.705791e+11 5.513161e+10 \n",
- "57414 000002.SZ 2020 3.498445e+11 5.929812e+10 \n",
- "59180 000002.SZ 2021 3.927728e+11 3.806953e+10 \n",
- "62929 000002.SZ 2022 4.049915e+11 3.755091e+10 \n",
- "68422 000002.SZ 2023 4.029335e+11 2.045556e+10 \n",
+ "0 0 0 0.000000e+00 0.000000e+00 \n",
+ "1 000001.SZ 2006 6.474463e+09 1.302907e+09 \n",
+ "2 000001.SZ 2007 1.300606e+10 2.649903e+09 \n",
+ "3 000001.SZ 2008 1.640079e+10 6.140350e+08 \n",
+ "4 000001.SZ 2009 2.046961e+10 5.030729e+09 \n",
+ "... ... ... ... ... \n",
+ "70725 871981.BJ 2019 1.484536e+08 1.933833e+07 \n",
+ "70726 871981.BJ 2020 1.963500e+08 3.113004e+07 \n",
+ "70727 871981.BJ 2021 4.901179e+08 6.549797e+07 \n",
+ "70728 871981.BJ 2022 5.238630e+08 4.359533e+07 \n",
+ "70729 871981.BJ 2023 5.044336e+08 -5.665176e+06 \n",
"\n",
" total_assets total_revenue inventories accounts_receivable \\\n",
- "1945 2.199239e+10 1.055885e+10 1.484948e+10 3.773077e+08 \n",
- "3432 4.991984e+10 1.791833e+10 3.416711e+10 3.646097e+08 \n",
- "5449 1.000945e+11 3.552661e+10 6.647288e+10 8.648830e+08 \n",
- "7921 1.192366e+11 4.099178e+10 8.589870e+10 9.227748e+08 \n",
- "10605 1.376086e+11 4.888101e+10 9.008529e+10 7.131919e+08 \n",
- "13934 2.156376e+11 5.071385e+10 1.333335e+11 1.594025e+09 \n",
- "17289 2.962084e+11 7.178275e+10 2.083355e+11 1.514814e+09 \n",
- "20376 3.788016e+11 1.031162e+11 2.551641e+11 1.886549e+09 \n",
- "25215 4.792053e+11 1.354188e+11 3.311332e+11 3.078970e+09 \n",
- "29387 5.084088e+11 1.463880e+11 3.177264e+11 1.894072e+09 \n",
- "33753 6.112956e+11 1.955491e+11 3.681219e+11 2.510653e+09 \n",
- "37463 8.306742e+11 2.404772e+11 4.673613e+11 2.075257e+09 \n",
- "42678 1.165347e+12 2.428971e+11 5.980877e+11 1.432734e+09 \n",
- "47756 1.528579e+12 2.976793e+11 7.503026e+11 1.586181e+09 \n",
- "52944 1.729929e+12 3.678939e+11 8.970190e+11 1.988076e+09 \n",
- "57414 1.869177e+12 4.191117e+11 1.002063e+12 2.992423e+09 \n",
- "59180 1.938638e+12 4.527978e+11 1.075617e+12 4.743597e+09 \n",
- "62929 1.757124e+12 5.038384e+11 9.070569e+11 7.504692e+09 \n",
- "68422 1.504850e+12 4.657391e+11 7.016958e+11 7.293628e+09 \n",
+ "0 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 \n",
+ "1 2.605763e+11 7.135218e+09 NaN NaN \n",
+ "2 3.525394e+11 1.080750e+10 NaN NaN \n",
+ "3 4.744402e+11 1.451312e+10 NaN NaN \n",
+ "4 5.878110e+11 1.511444e+10 NaN NaN \n",
+ "... ... ... ... ... \n",
+ "70725 3.438787e+08 2.288707e+08 6.439933e+07 9.145441e+07 \n",
+ "70726 4.407381e+08 3.221584e+08 7.076865e+07 1.028702e+08 \n",
+ "70727 7.806398e+08 4.748939e+08 1.102946e+08 1.094223e+08 \n",
+ "70728 8.141886e+08 3.872667e+08 1.034502e+08 7.252802e+07 \n",
+ "70729 7.671820e+08 3.613133e+08 1.070212e+08 7.962033e+07 \n",
"\n",
- " operating_costs operating_profit cash \\\n",
- "1945 6.884921e+09 1.958371e+09 3.249035e+09 \n",
- "3432 1.144126e+10 3.426907e+09 1.074370e+10 \n",
- "5449 2.060734e+10 7.652897e+09 1.704650e+10 \n",
- "7921 2.500527e+10 6.364790e+09 1.997829e+10 \n",
- "10605 3.451472e+10 8.685083e+09 2.300192e+10 \n",
- "13934 3.007350e+10 1.189489e+10 3.781693e+10 \n",
- "17289 4.322816e+10 1.576322e+10 3.423951e+10 \n",
- "20376 6.542161e+10 2.101304e+10 5.229154e+10 \n",
- "25215 9.279765e+10 2.426134e+10 4.436541e+10 \n",
- "29387 1.025571e+11 2.497936e+10 6.271525e+10 \n",
- "33753 1.381506e+11 3.312278e+10 5.318038e+10 \n",
- "37463 1.697424e+11 3.902378e+10 8.703212e+10 \n",
- "42678 1.600799e+11 5.081292e+10 1.741210e+11 \n",
- "47756 1.861042e+11 6.749861e+10 1.884174e+11 \n",
- "52944 2.345503e+11 7.661314e+10 1.661946e+11 \n",
- "57414 2.965407e+11 7.995864e+10 1.952307e+11 \n",
- "59180 3.539771e+11 5.253100e+10 1.493524e+11 \n",
- "62929 4.053193e+11 5.200694e+10 1.372076e+11 \n",
- "68422 3.947839e+11 2.925170e+10 9.981376e+10 \n",
+ " operating_costs operating_profit ... score_operating_safety_margin \\\n",
+ "0 0.000000e+00 0.000000e+00 ... 0 \n",
+ "1 NaN 1.905169e+09 ... 0 \n",
+ "2 NaN 3.721942e+09 ... 0 \n",
+ "3 NaN 8.034260e+08 ... 0 \n",
+ "4 NaN 6.159127e+09 ... 0 \n",
+ "... ... ... ... ... \n",
+ "70725 1.759984e+08 1.982603e+07 ... 0 \n",
+ "70726 2.444144e+08 3.466142e+07 ... 0 \n",
+ "70727 3.501988e+08 7.194507e+07 ... 0 \n",
+ "70728 3.141146e+08 2.827675e+07 ... 0 \n",
+ "70729 3.220560e+08 -1.192680e+07 ... 0 \n",
"\n",
- " operating_net_cash_flow score prev_total_stockholder_interest \\\n",
- "1945 8.434391e+08 0.0 NaN \n",
- "3432 -3.024121e+09 0.0 8.581223e+09 \n",
- "5449 -1.043772e+10 0.0 1.745350e+10 \n",
- "7921 -3.415183e+07 0.0 3.391952e+10 \n",
- "10605 9.253351e+09 0.0 3.881855e+10 \n",
- "13934 2.237255e+09 250.0 4.540851e+10 \n",
- "17289 3.389425e+09 0.0 5.458620e+10 \n",
- "20376 3.725958e+09 0.0 6.783254e+10 \n",
- "25215 1.923869e+09 300.0 8.213819e+10 \n",
- "29387 4.172482e+10 0.0 1.054394e+11 \n",
- "33753 1.604602e+10 0.0 1.158936e+11 \n",
- "37463 3.956613e+10 400.0 1.363096e+11 \n",
- "42678 8.232283e+10 250.0 1.616766e+11 \n",
- "47756 3.361818e+10 0.0 1.866739e+11 \n",
- "52944 4.568681e+10 400.0 2.356207e+11 \n",
- "57414 5.318802e+10 0.0 2.705791e+11 \n",
- "59180 4.113161e+09 250.0 3.498445e+11 \n",
- "62929 2.750449e+09 0.0 3.927728e+11 \n",
- "68422 3.912324e+09 300.0 4.049915e+11 \n",
+ " net_income_shift_1 score_net_income_1 net_income_shift_2 \\\n",
+ "0 0.000000e+00 0 NaN \n",
+ "1 3.110076e+08 30 NaN \n",
+ "2 1.302907e+09 30 0.000000e+00 \n",
+ "3 2.649903e+09 -30 1.302907e+09 \n",
+ "4 6.140350e+08 30 2.649903e+09 \n",
+ "... ... ... ... \n",
+ "70725 1.875294e+07 30 9.625220e+06 \n",
+ "70726 1.933833e+07 30 1.875294e+07 \n",
+ "70727 3.113004e+07 30 1.933833e+07 \n",
+ "70728 6.549797e+07 -30 3.113004e+07 \n",
+ "70729 4.359533e+07 -30 6.549797e+07 \n",
"\n",
- " roe average_roe \n",
- "1945 NaN NaN \n",
- "3432 0.186136 NaN \n",
- "5449 0.207015 NaN \n",
- "7921 0.127577 NaN \n",
- "10605 0.152683 NaN \n",
- "13934 0.176802 0.170043 \n",
- "17289 0.189507 0.170717 \n",
- "20376 0.208875 0.171089 \n",
- "25215 0.195093 0.184592 \n",
- "29387 0.174285 0.188912 \n",
- "33753 0.205782 0.194708 \n",
- "37463 0.190279 0.194863 \n",
- "42678 0.213626 0.195813 \n",
- "47756 0.233355 0.203465 \n",
- "52944 0.217825 0.212174 \n",
- "57414 0.191154 0.209248 \n",
- "59180 0.102528 0.191698 \n",
- "62929 0.094140 0.167801 \n",
- "68422 0.050637 0.131257 "
+ " score_net_income_2 net_income_shift_3 score_net_income_3 \\\n",
+ "0 -25 NaN -20 \n",
+ "1 -25 NaN -20 \n",
+ "2 25 NaN -20 \n",
+ "3 25 0.000000e+00 20 \n",
+ "4 -25 1.302907e+09 20 \n",
+ "... ... ... ... \n",
+ "70725 25 0.000000e+00 20 \n",
+ "70726 25 9.625220e+06 20 \n",
+ "70727 25 1.875294e+07 20 \n",
+ "70728 25 1.933833e+07 20 \n",
+ "70729 -25 3.113004e+07 20 \n",
+ "\n",
+ " net_income_shift_4 score_net_income_4 score_net_income_ascending \n",
+ "0 NaN -15 -60 \n",
+ "1 NaN -15 -30 \n",
+ "2 NaN -15 20 \n",
+ "3 NaN -15 0 \n",
+ "4 0.00 15 40 \n",
+ "... ... ... ... \n",
+ "70725 NaN -15 60 \n",
+ "70726 0.00 15 90 \n",
+ "70727 9625220.11 15 90 \n",
+ "70728 18752944.38 15 30 \n",
+ "70729 19338331.78 15 -20 \n",
+ "\n",
+ "[70730 rows x 46 columns]"
],
"text/html": [
"\n",
@@ -383,801 +549,299 @@
"
accounts_receivable | \n",
" operating_costs | \n",
" operating_profit | \n",
- " cash | \n",
- " operating_net_cash_flow | \n",
- " score | \n",
- " prev_total_stockholder_interest | \n",
- " roe | \n",
- " average_roe | \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " | 1945 | \n",
- " 000002.SZ | \n",
- " 2005 | \n",
- " 8.581223e+09 | \n",
- " 1.433426e+09 | \n",
- " 2.199239e+10 | \n",
- " 1.055885e+10 | \n",
- " 1.484948e+10 | \n",
- " 3.773077e+08 | \n",
- " 6.884921e+09 | \n",
- " 1.958371e+09 | \n",
- " 3.249035e+09 | \n",
- " 8.434391e+08 | \n",
- " 0.0 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " | 3432 | \n",
- " 000002.SZ | \n",
- " 2006 | \n",
- " 1.745350e+10 | \n",
- " 2.422997e+09 | \n",
- " 4.991984e+10 | \n",
- " 1.791833e+10 | \n",
- " 3.416711e+10 | \n",
- " 3.646097e+08 | \n",
- " 1.144126e+10 | \n",
- " 3.426907e+09 | \n",
- " 1.074370e+10 | \n",
- " -3.024121e+09 | \n",
- " 0.0 | \n",
- " 8.581223e+09 | \n",
- " 0.186136 | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " | 5449 | \n",
- " 000002.SZ | \n",
- " 2007 | \n",
- " 3.391952e+10 | \n",
- " 5.317501e+09 | \n",
- " 1.000945e+11 | \n",
- " 3.552661e+10 | \n",
- " 6.647288e+10 | \n",
- " 8.648830e+08 | \n",
- " 2.060734e+10 | \n",
- " 7.652897e+09 | \n",
- " 1.704650e+10 | \n",
- " -1.043772e+10 | \n",
- " 0.0 | \n",
- " 1.745350e+10 | \n",
- " 0.207015 | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " | 7921 | \n",
- " 000002.SZ | \n",
- " 2008 | \n",
- " 3.881855e+10 | \n",
- " 4.639869e+09 | \n",
- " 1.192366e+11 | \n",
- " 4.099178e+10 | \n",
- " 8.589870e+10 | \n",
- " 9.227748e+08 | \n",
- " 2.500527e+10 | \n",
- " 6.364790e+09 | \n",
- " 1.997829e+10 | \n",
- " -3.415183e+07 | \n",
- " 0.0 | \n",
- " 3.391952e+10 | \n",
- " 0.127577 | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " | 10605 | \n",
- " 000002.SZ | \n",
- " 2009 | \n",
- " 4.540851e+10 | \n",
- " 6.430008e+09 | \n",
- " 1.376086e+11 | \n",
- " 4.888101e+10 | \n",
- " 9.008529e+10 | \n",
- " 7.131919e+08 | \n",
- " 3.451472e+10 | \n",
- " 8.685083e+09 | \n",
- " 2.300192e+10 | \n",
- " 9.253351e+09 | \n",
- " 0.0 | \n",
- " 3.881855e+10 | \n",
- " 0.152683 | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " | 13934 | \n",
- " 000002.SZ | \n",
- " 2010 | \n",
- " 5.458620e+10 | \n",
- " 8.839611e+09 | \n",
- " 2.156376e+11 | \n",
- " 5.071385e+10 | \n",
- " 1.333335e+11 | \n",
- " 1.594025e+09 | \n",
- " 3.007350e+10 | \n",
- " 1.189489e+10 | \n",
- " 3.781693e+10 | \n",
- " 2.237255e+09 | \n",
- " 250.0 | \n",
- " 4.540851e+10 | \n",
- " 0.176802 | \n",
- " 0.170043 | \n",
- "
\n",
- " \n",
- " | 17289 | \n",
- " 000002.SZ | \n",
- " 2011 | \n",
- " 6.783254e+10 | \n",
- " 1.159961e+10 | \n",
- " 2.962084e+11 | \n",
- " 7.178275e+10 | \n",
- " 2.083355e+11 | \n",
- " 1.514814e+09 | \n",
- " 4.322816e+10 | \n",
- " 1.576322e+10 | \n",
- " 3.423951e+10 | \n",
- " 3.389425e+09 | \n",
- " 0.0 | \n",
- " 5.458620e+10 | \n",
- " 0.189507 | \n",
- " 0.170717 | \n",
- "
\n",
- " \n",
- " | 20376 | \n",
- " 000002.SZ | \n",
- " 2012 | \n",
- " 8.213819e+10 | \n",
- " 1.566259e+10 | \n",
- " 3.788016e+11 | \n",
- " 1.031162e+11 | \n",
- " 2.551641e+11 | \n",
- " 1.886549e+09 | \n",
- " 6.542161e+10 | \n",
- " 2.101304e+10 | \n",
- " 5.229154e+10 | \n",
- " 3.725958e+09 | \n",
- " 0.0 | \n",
- " 6.783254e+10 | \n",
- " 0.208875 | \n",
- " 0.171089 | \n",
- "
\n",
- " \n",
- " | 25215 | \n",
- " 000002.SZ | \n",
- " 2013 | \n",
- " 1.054394e+11 | \n",
- " 1.829755e+10 | \n",
- " 4.792053e+11 | \n",
- " 1.354188e+11 | \n",
- " 3.311332e+11 | \n",
- " 3.078970e+09 | \n",
- " 9.279765e+10 | \n",
- " 2.426134e+10 | \n",
- " 4.436541e+10 | \n",
- " 1.923869e+09 | \n",
- " 300.0 | \n",
- " 8.213819e+10 | \n",
- " 0.195093 | \n",
- " 0.184592 | \n",
- "
\n",
- " \n",
- " | 29387 | \n",
- " 000002.SZ | \n",
- " 2014 | \n",
- " 1.158936e+11 | \n",
- " 1.928752e+10 | \n",
- " 5.084088e+11 | \n",
- " 1.463880e+11 | \n",
- " 3.177264e+11 | \n",
- " 1.894072e+09 | \n",
- " 1.025571e+11 | \n",
- " 2.497936e+10 | \n",
- " 6.271525e+10 | \n",
- " 4.172482e+10 | \n",
- " 0.0 | \n",
- " 1.054394e+11 | \n",
- " 0.174285 | \n",
- " 0.188912 | \n",
- "
\n",
- " \n",
- " | 33753 | \n",
- " 000002.SZ | \n",
- " 2015 | \n",
- " 1.363096e+11 | \n",
- " 2.594944e+10 | \n",
- " 6.112956e+11 | \n",
- " 1.955491e+11 | \n",
- " 3.681219e+11 | \n",
- " 2.510653e+09 | \n",
- " 1.381506e+11 | \n",
- " 3.312278e+10 | \n",
- " 5.318038e+10 | \n",
- " 1.604602e+10 | \n",
- " 0.0 | \n",
- " 1.158936e+11 | \n",
- " 0.205782 | \n",
- " 0.194708 | \n",
- "
\n",
- " \n",
- " | 37463 | \n",
- " 000002.SZ | \n",
- " 2016 | \n",
- " 1.616766e+11 | \n",
- " 2.835026e+10 | \n",
- " 8.306742e+11 | \n",
- " 2.404772e+11 | \n",
- " 4.673613e+11 | \n",
- " 2.075257e+09 | \n",
- " 1.697424e+11 | \n",
- " 3.902378e+10 | \n",
- " 8.703212e+10 | \n",
- " 3.956613e+10 | \n",
- " 400.0 | \n",
- " 1.363096e+11 | \n",
- " 0.190279 | \n",
- " 0.194863 | \n",
- "
\n",
- " \n",
- " | 42678 | \n",
- " 000002.SZ | \n",
- " 2017 | \n",
- " 1.866739e+11 | \n",
- " 3.720839e+10 | \n",
- " 1.165347e+12 | \n",
- " 2.428971e+11 | \n",
- " 5.980877e+11 | \n",
- " 1.432734e+09 | \n",
- " 1.600799e+11 | \n",
- " 5.081292e+10 | \n",
- " 1.741210e+11 | \n",
- " 8.232283e+10 | \n",
- " 250.0 | \n",
- " 1.616766e+11 | \n",
- " 0.213626 | \n",
- " 0.195813 | \n",
- "
\n",
- " \n",
- " | 47756 | \n",
- " 000002.SZ | \n",
- " 2018 | \n",
- " 2.356207e+11 | \n",
- " 4.927229e+10 | \n",
- " 1.528579e+12 | \n",
- " 2.976793e+11 | \n",
- " 7.503026e+11 | \n",
- " 1.586181e+09 | \n",
- " 1.861042e+11 | \n",
- " 6.749861e+10 | \n",
- " 1.884174e+11 | \n",
- " 3.361818e+10 | \n",
- " 0.0 | \n",
- " 1.866739e+11 | \n",
- " 0.233355 | \n",
- " 0.203465 | \n",
- "
\n",
- " \n",
- " | 52944 | \n",
- " 000002.SZ | \n",
- " 2019 | \n",
- " 2.705791e+11 | \n",
- " 5.513161e+10 | \n",
- " 1.729929e+12 | \n",
- " 3.678939e+11 | \n",
- " 8.970190e+11 | \n",
- " 1.988076e+09 | \n",
- " 2.345503e+11 | \n",
- " 7.661314e+10 | \n",
- " 1.661946e+11 | \n",
- " 4.568681e+10 | \n",
- " 400.0 | \n",
- " 2.356207e+11 | \n",
- " 0.217825 | \n",
- " 0.212174 | \n",
- "
\n",
- " \n",
- " | 57414 | \n",
- " 000002.SZ | \n",
- " 2020 | \n",
- " 3.498445e+11 | \n",
- " 5.929812e+10 | \n",
- " 1.869177e+12 | \n",
- " 4.191117e+11 | \n",
- " 1.002063e+12 | \n",
- " 2.992423e+09 | \n",
- " 2.965407e+11 | \n",
- " 7.995864e+10 | \n",
- " 1.952307e+11 | \n",
- " 5.318802e+10 | \n",
- " 0.0 | \n",
- " 2.705791e+11 | \n",
- " 0.191154 | \n",
- " 0.209248 | \n",
- "
\n",
- " \n",
- " | 59180 | \n",
- " 000002.SZ | \n",
- " 2021 | \n",
- " 3.927728e+11 | \n",
- " 3.806953e+10 | \n",
- " 1.938638e+12 | \n",
- " 4.527978e+11 | \n",
- " 1.075617e+12 | \n",
- " 4.743597e+09 | \n",
- " 3.539771e+11 | \n",
- " 5.253100e+10 | \n",
- " 1.493524e+11 | \n",
- " 4.113161e+09 | \n",
- " 250.0 | \n",
- " 3.498445e+11 | \n",
- " 0.102528 | \n",
- " 0.191698 | \n",
- "
\n",
- " \n",
- " | 62929 | \n",
- " 000002.SZ | \n",
- " 2022 | \n",
- " 4.049915e+11 | \n",
- " 3.755091e+10 | \n",
- " 1.757124e+12 | \n",
- " 5.038384e+11 | \n",
- " 9.070569e+11 | \n",
- " 7.504692e+09 | \n",
- " 4.053193e+11 | \n",
- " 5.200694e+10 | \n",
- " 1.372076e+11 | \n",
- " 2.750449e+09 | \n",
- " 0.0 | \n",
- " 3.927728e+11 | \n",
- " 0.094140 | \n",
- " 0.167801 | \n",
- "
\n",
- " \n",
- " | 68422 | \n",
- " 000002.SZ | \n",
- " 2023 | \n",
- " 4.029335e+11 | \n",
- " 2.045556e+10 | \n",
- " 1.504850e+12 | \n",
- " 4.657391e+11 | \n",
- " 7.016958e+11 | \n",
- " 7.293628e+09 | \n",
- " 3.947839e+11 | \n",
- " 2.925170e+10 | \n",
- " 9.981376e+10 | \n",
- " 3.912324e+09 | \n",
- " 300.0 | \n",
- " 4.049915e+11 | \n",
- " 0.050637 | \n",
- " 0.131257 | \n",
- "
\n",
- " \n",
- "\n",
- ""
- ]
- },
- "execution_count": 150,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 150
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-17T10:19:25.031141Z",
- "start_time": "2025-01-17T10:19:25.020325Z"
- }
- },
- "cell_type": "code",
- "source": [
- "df = pd.DataFrame([[1, 2, 0], [1, 3, 0], [1, -4, 0]], columns=[\"code\", \"average\", \"score\"])\n",
- "df[\"condition\"] = df.groupby(\"code\")[\"average\"].transform(\n",
- " lambda x: x.rolling(window=2).apply(lambda y: (y < 0).any(), raw=False)\n",
- ") > 0\n",
- "df[\"score\"].mask(\n",
- " df.groupby(\"code\")[\"average\"].transform(\n",
- " lambda x: x.rolling(window=2).apply(lambda y: (y < 0).any(), raw=False)\n",
- " ) > 0,\n",
- " 0\n",
- ")\n",
- "df"
- ],
- "id": "1a6a739df5b6f3a9",
- "outputs": [
- {
- "data": {
- "text/plain": [
- " code average score condition\n",
- "0 1 2 0 False\n",
- "1 1 3 0 False\n",
- "2 1 -4 0 True"
- ],
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " code | \n",
- " average | \n",
- " score | \n",
- " condition | \n",
+ " ... | \n",
+ " score_operating_safety_margin | \n",
+ " net_income_shift_1 | \n",
+ " score_net_income_1 | \n",
+ " net_income_shift_2 | \n",
+ " score_net_income_2 | \n",
+ " net_income_shift_3 | \n",
+ " score_net_income_3 | \n",
+ " net_income_shift_4 | \n",
+ " score_net_income_4 | \n",
+ " score_net_income_ascending | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
- " 1 | \n",
- " 2 | \n",
" 0 | \n",
- " False | \n",
+ " 0 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " 0.000000e+00 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 0.000000e+00 | \n",
+ " 0 | \n",
+ " NaN | \n",
+ " -25 | \n",
+ " NaN | \n",
+ " -20 | \n",
+ " NaN | \n",
+ " -15 | \n",
+ " -60 | \n",
"
\n",
" \n",
" | 1 | \n",
- " 1 | \n",
- " 3 | \n",
+ " 000001.SZ | \n",
+ " 2006 | \n",
+ " 6.474463e+09 | \n",
+ " 1.302907e+09 | \n",
+ " 2.605763e+11 | \n",
+ " 7.135218e+09 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 1.905169e+09 | \n",
+ " ... | \n",
" 0 | \n",
- " False | \n",
+ " 3.110076e+08 | \n",
+ " 30 | \n",
+ " NaN | \n",
+ " -25 | \n",
+ " NaN | \n",
+ " -20 | \n",
+ " NaN | \n",
+ " -15 | \n",
+ " -30 | \n",
"
\n",
" \n",
" | 2 | \n",
- " 1 | \n",
- " -4 | \n",
+ " 000001.SZ | \n",
+ " 2007 | \n",
+ " 1.300606e+10 | \n",
+ " 2.649903e+09 | \n",
+ " 3.525394e+11 | \n",
+ " 1.080750e+10 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 3.721942e+09 | \n",
+ " ... | \n",
" 0 | \n",
- " True | \n",
+ " 1.302907e+09 | \n",
+ " 30 | \n",
+ " 0.000000e+00 | \n",
+ " 25 | \n",
+ " NaN | \n",
+ " -20 | \n",
+ " NaN | \n",
+ " -15 | \n",
+ " 20 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 000001.SZ | \n",
+ " 2008 | \n",
+ " 1.640079e+10 | \n",
+ " 6.140350e+08 | \n",
+ " 4.744402e+11 | \n",
+ " 1.451312e+10 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 8.034260e+08 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 2.649903e+09 | \n",
+ " -30 | \n",
+ " 1.302907e+09 | \n",
+ " 25 | \n",
+ " 0.000000e+00 | \n",
+ " 20 | \n",
+ " NaN | \n",
+ " -15 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 000001.SZ | \n",
+ " 2009 | \n",
+ " 2.046961e+10 | \n",
+ " 5.030729e+09 | \n",
+ " 5.878110e+11 | \n",
+ " 1.511444e+10 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 6.159127e+09 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 6.140350e+08 | \n",
+ " 30 | \n",
+ " 2.649903e+09 | \n",
+ " -25 | \n",
+ " 1.302907e+09 | \n",
+ " 20 | \n",
+ " 0.00 | \n",
+ " 15 | \n",
+ " 40 | \n",
+ "
\n",
+ " \n",
+ " | ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " | 70725 | \n",
+ " 871981.BJ | \n",
+ " 2019 | \n",
+ " 1.484536e+08 | \n",
+ " 1.933833e+07 | \n",
+ " 3.438787e+08 | \n",
+ " 2.288707e+08 | \n",
+ " 6.439933e+07 | \n",
+ " 9.145441e+07 | \n",
+ " 1.759984e+08 | \n",
+ " 1.982603e+07 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 1.875294e+07 | \n",
+ " 30 | \n",
+ " 9.625220e+06 | \n",
+ " 25 | \n",
+ " 0.000000e+00 | \n",
+ " 20 | \n",
+ " NaN | \n",
+ " -15 | \n",
+ " 60 | \n",
+ "
\n",
+ " \n",
+ " | 70726 | \n",
+ " 871981.BJ | \n",
+ " 2020 | \n",
+ " 1.963500e+08 | \n",
+ " 3.113004e+07 | \n",
+ " 4.407381e+08 | \n",
+ " 3.221584e+08 | \n",
+ " 7.076865e+07 | \n",
+ " 1.028702e+08 | \n",
+ " 2.444144e+08 | \n",
+ " 3.466142e+07 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 1.933833e+07 | \n",
+ " 30 | \n",
+ " 1.875294e+07 | \n",
+ " 25 | \n",
+ " 9.625220e+06 | \n",
+ " 20 | \n",
+ " 0.00 | \n",
+ " 15 | \n",
+ " 90 | \n",
+ "
\n",
+ " \n",
+ " | 70727 | \n",
+ " 871981.BJ | \n",
+ " 2021 | \n",
+ " 4.901179e+08 | \n",
+ " 6.549797e+07 | \n",
+ " 7.806398e+08 | \n",
+ " 4.748939e+08 | \n",
+ " 1.102946e+08 | \n",
+ " 1.094223e+08 | \n",
+ " 3.501988e+08 | \n",
+ " 7.194507e+07 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 3.113004e+07 | \n",
+ " 30 | \n",
+ " 1.933833e+07 | \n",
+ " 25 | \n",
+ " 1.875294e+07 | \n",
+ " 20 | \n",
+ " 9625220.11 | \n",
+ " 15 | \n",
+ " 90 | \n",
+ "
\n",
+ " \n",
+ " | 70728 | \n",
+ " 871981.BJ | \n",
+ " 2022 | \n",
+ " 5.238630e+08 | \n",
+ " 4.359533e+07 | \n",
+ " 8.141886e+08 | \n",
+ " 3.872667e+08 | \n",
+ " 1.034502e+08 | \n",
+ " 7.252802e+07 | \n",
+ " 3.141146e+08 | \n",
+ " 2.827675e+07 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 6.549797e+07 | \n",
+ " -30 | \n",
+ " 3.113004e+07 | \n",
+ " 25 | \n",
+ " 1.933833e+07 | \n",
+ " 20 | \n",
+ " 18752944.38 | \n",
+ " 15 | \n",
+ " 30 | \n",
+ "
\n",
+ " \n",
+ " | 70729 | \n",
+ " 871981.BJ | \n",
+ " 2023 | \n",
+ " 5.044336e+08 | \n",
+ " -5.665176e+06 | \n",
+ " 7.671820e+08 | \n",
+ " 3.613133e+08 | \n",
+ " 1.070212e+08 | \n",
+ " 7.962033e+07 | \n",
+ " 3.220560e+08 | \n",
+ " -1.192680e+07 | \n",
+ " ... | \n",
+ " 0 | \n",
+ " 4.359533e+07 | \n",
+ " -30 | \n",
+ " 6.549797e+07 | \n",
+ " -25 | \n",
+ " 3.113004e+07 | \n",
+ " 20 | \n",
+ " 19338331.78 | \n",
+ " 15 | \n",
+ " -20 | \n",
"
\n",
" \n",
"
\n",
+ "
70730 rows × 46 columns
\n",
"
"
]
},
- "execution_count": 165,
+ "execution_count": 469,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 165
+ "execution_count": 469
},
{
"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-14T14:23:20.494927Z",
- "start_time": "2025-01-14T14:23:12.064079Z"
- }
- },
- "cell_type": "code",
- "source": [
- "def cal_roa(df):\n",
- " df[\"prev_total_assets\"] = df[\"total_assets\"].shift(1)\n",
- " df[\"roa\"] = df[\"net_income\"] / ((df[\"prev_total_assets\"] + df[\"total_assets\"]) / 2)\n",
- " df.drop(columns=[\"prev_total_assets\"], inplace=True)\n",
- "\n",
- "\n",
- "def score_by_roa(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- " cal_roa(temp_df)\n",
- "\n",
- " average_roa = temp_df.nlargest(5, \"year\")[\"roa\"].mean() * 100\n",
- "\n",
- " if average_roa >= 15:\n",
- " return 100\n",
- " elif average_roa >= 11:\n",
- " return 80\n",
- " elif average_roa >= 7:\n",
- " return 50\n",
- " else:\n",
- " return 0\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_roa(x[0])), codes))"
- ],
- "id": "25d1d5c0f7de460c",
- "outputs": [],
- "execution_count": 8
- },
- {
- "metadata": {},
- "cell_type": "markdown",
- "source": [
- "税后净利 规模(百万)\t获利规模大,那股价的”长期上涨潜力“也就会越稳健、越确定。选择时,大公司的优先级要高于小公司。\n",
- "税后净利均值 >= 10000\t150分\n",
- "10000 > 税后净利均值 >= 1000\t100分\n",
- "1000 > 税后净利均值\t0分"
- ],
- "id": "dbcb1d6b23582f3e"
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-14T14:23:29.214393Z",
- "start_time": "2025-01-14T14:23:22.256675Z"
- }
- },
- "cell_type": "code",
- "source": [
- "def score_by_net_income(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- " average_net_income = temp_df.nlargest(5, \"year\")[\"net_income\"].mean()\n",
- "\n",
- " if average_net_income >= 10000 * 10000000:\n",
- " return 150\n",
- " elif average_net_income >= 1000 * 10000000:\n",
- " return 100\n",
- " else:\n",
- " return 0\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_net_income(x[0])), codes))"
- ],
- "id": "2f19c7fbb0afaa49",
- "outputs": [],
- "execution_count": 9
- },
- {
- "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-14T14:23:39.246944Z",
- "start_time": "2025-01-14T14:23:30.739476Z"
- }
- },
- "cell_type": "code",
- "source": [
- "def cal_total_assets_turnover_ratio(df):\n",
- " df[\"prev_total_assets\"] = df[\"total_assets\"].shift(1)\n",
- " df[\"total_assets_turnover_ratio\"] = df[\"total_revenue\"] / ((df[\"prev_total_assets\"] + df[\"total_assets\"]) / 2)\n",
- " df.drop(columns=[\"prev_total_assets\"], inplace=True)\n",
- "\n",
- "\n",
- "def cal_cash_ratio(df):\n",
- " df[\"cash_ratio\"] = df[\"cash\"] / df[\"total_assets\"]\n",
- "\n",
- "\n",
- "def score_by_assets_turnover_and_cash(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- "\n",
- " # 总资产周转率\n",
- " cal_total_assets_turnover_ratio(temp_df)\n",
- " total_assets_turnover_ratio = \\\n",
- " temp_df[temp_df[\"year\"] == temp_df[\"year\"].max()][\"total_assets_turnover_ratio\"].values[0] * 100\n",
- "\n",
- " # 现金比率\n",
- " cal_cash_ratio(temp_df)\n",
- " cash_ratio = temp_df[temp_df[\"year\"] == temp_df[\"year\"].max()][\"cash_ratio\"].values[0] * 100\n",
- "\n",
- " if total_assets_turnover_ratio > 80 and cash_ratio >= 10:\n",
- " return 50\n",
- " elif total_assets_turnover_ratio < 80 and cash_ratio >= 20:\n",
- " return 50\n",
- " else:\n",
- " return 0\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_assets_turnover_and_cash(x[0])), codes))"
- ],
- "id": "31be2cb671b7adde",
- "outputs": [],
- "execution_count": 10
- },
- {
- "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-14T14:23:47.733800Z",
- "start_time": "2025-01-14T14:23:40.102117Z"
- }
- },
- "cell_type": "code",
- "source": [
- "# 收现日数\n",
- "def cal_collection_cash_period(df):\n",
- " df[\"collection_cash_period\"] = 360 / (df[\"total_revenue\"] / df[\"accounts_receivable\"])\n",
- "\n",
- "\n",
- "# 销货日数\n",
- "def cal_sales_period(df):\n",
- " df[\"sales_period\"] = 360 / (df[\"operating_costs\"] / df[\"inventories\"])\n",
- "\n",
- "\n",
- "def score_by_collection_cash_period_and_sales_period(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- "\n",
- " cal_collection_cash_period(temp_df)\n",
- " collection_cash_period = temp_df[temp_df[\"year\"] == temp_df[\"year\"].max()][\"collection_cash_period\"].values[0]\n",
- "\n",
- " cal_sales_period(temp_df)\n",
- " sales_period = temp_df[temp_df[\"year\"] == temp_df[\"year\"].max()][\"sales_period\"].values[0]\n",
- "\n",
- " score = 0\n",
- " if collection_cash_period < 30:\n",
- " score += 20\n",
- "\n",
- " if sales_period < 30:\n",
- " score += 20\n",
- "\n",
- " if (collection_cash_period + sales_period) < 40:\n",
- " score += 20\n",
- " elif (collection_cash_period + sales_period) < 60:\n",
- " score += 10\n",
- "\n",
- " return score\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_collection_cash_period_and_sales_period(x[0])), codes))"
- ],
- "id": "ab6ff79c2650db7c",
- "outputs": [],
- "execution_count": 11
- },
- {
- "metadata": {},
- "cell_type": "markdown",
- "source": [
- "毛利率(%)\t毛利率 是否保持平稳,不大起大落。\n",
- "30% >= 毛利率平均波动幅度\t50分\n",
- "毛利率平均波动幅度 > 30%\t0分"
- ],
- "id": "a53bfdb799df8f48"
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-14T14:23:57.280972Z",
- "start_time": "2025-01-14T14:23:49.457909Z"
- }
- },
- "cell_type": "code",
- "source": [
- "# 毛利率\n",
- "def cal_gross_profit_ratio(df):\n",
- " df[\"gross_profit_ratio\"] = (df[\"total_revenue\"] - df[\"operating_costs\"]) / df[\"total_revenue\"]\n",
- "\n",
- "\n",
- "def score_by_gross_profit_ratio_volatility(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- " cal_gross_profit_ratio(temp_df)\n",
- " gross_profit_ratio_std = temp_df.nlargest(5, \"year\")[\"gross_profit_ratio\"].std() * 100\n",
- "\n",
- " if gross_profit_ratio_std < 30:\n",
- " return 50\n",
- " else:\n",
- " return 0\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_gross_profit_ratio_volatility(x[0])), codes))"
- ],
- "id": "8e58e0114851ebcb",
- "outputs": [],
- "execution_count": 12
- },
- {
- "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-14T14:24:05.675449Z",
- "start_time": "2025-01-14T14:23:58.156821Z"
- }
- },
- "cell_type": "code",
- "source": [
- "# 经营安全边际\n",
- "def cal_operating_safety_margin(df):\n",
- " # 经营利润率\n",
- " df[\"operating_profit_ratio\"] = df[\"operating_profit\"] / df[\"total_revenue\"]\n",
- " df[\"operating_safety_margin\"] = df[\"operating_profit_ratio\"] / df[\"gross_profit_ratio\"]\n",
- "\n",
- "\n",
- "def score_by_operating_safety_margin(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- " cal_gross_profit_ratio(temp_df)\n",
- " cal_operating_safety_margin(temp_df)\n",
- "\n",
- " operating_safety_margin = temp_df[temp_df[\"year\"] == temp_df[\"year\"].max()][\"operating_safety_margin\"].values[0]\n",
- "\n",
- " if operating_safety_margin >= 70:\n",
- " return 50\n",
- " elif operating_safety_margin >= 50:\n",
- " return 30\n",
- " elif operating_safety_margin >= 30:\n",
- " return 10\n",
- " else:\n",
- " return 0\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_operating_safety_margin(x[0])), codes))"
- ],
- "id": "d07048f574e163ab",
- "outputs": [],
- "execution_count": 13
- },
- {
- "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-14T14:24:13.783225Z",
- "start_time": "2025-01-14T14:24:06.605156Z"
- }
- },
"cell_type": "code",
"source": [
"def score_by_net_income_ascending(code):\n",
@@ -1213,15 +877,10 @@
],
"id": "4ab6a7b485dc9349",
"outputs": [],
- "execution_count": 14
+ "execution_count": null
},
{
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-14T14:24:21.962980Z",
- "start_time": "2025-01-14T14:24:14.785970Z"
- }
- },
+ "metadata": {},
"cell_type": "code",
"source": [
"def score_by_operating_net_cash_flow_ascending(code):\n",
@@ -1257,340 +916,36 @@
],
"id": "d6644089e803a79d",
"outputs": [],
- "execution_count": 15
+ "execution_count": null
},
{
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-14T14:24:24.969522Z",
- "start_time": "2025-01-14T14:24:24.957769Z"
- }
- },
+ "metadata": {},
"cell_type": "code",
"source": [
"df = pd.DataFrame(\n",
" codes,\n",
" columns=[\"code\", \"name\", \"score\", \"roe_score\", \"roa_score\", \"net_income\", \"assets_turnover_and_cash\",\n",
- " \"collection_cash_period_and_sales_period\", \"gross_profit_ratio_volatility\",\n",
- " \"operating_safety_margin\", \"net_income_ascending\",\n",
- " \"operating_net_cash_flow_ascending\"]\n",
+ " \"collection_cash_period_and_sales_period\", \"gross_profit_ratio_volatility\",\n",
+ " \"operating_safety_margin\", \"net_income_ascending\",\n",
+ " \"operating_net_cash_flow_ascending\"]\n",
")\n",
"df.sort_values(by=\"score\", ascending=False, inplace=True)\n",
"df"
],
"id": "ef9e6259efc1c1d0",
- "outputs": [
- {
- "data": {
- "text/plain": [
- " code name score roe_score roa_score net_income \\\n",
- "2393 600519.SH 贵州茅台 950 500 100 100 \n",
- "323 000858.SZ 五粮液 910 450 100 100 \n",
- "3238 603688.SH 石英股份 850 500 100 0 \n",
- "144 000568.SZ 泸州老窖 850 450 100 0 \n",
- "2336 600438.SH 通威股份 840 450 80 100 \n",
- "... ... ... ... ... ... ... \n",
- "1703 300436.SZ 广生堂 -100 0 0 0 \n",
- "2441 600579.SH 克劳斯 -100 0 0 0 \n",
- "1054 002672.SZ 东江环保 -130 0 0 0 \n",
- "1488 300204.SZ 舒泰神 -130 0 0 0 \n",
- "1619 300345.SZ 华民股份 -130 0 0 0 \n",
- "\n",
- " assets_turnover_and_cash collection_cash_period_and_sales_period \\\n",
- "2393 50 20 \n",
- "323 50 20 \n",
- "3238 50 0 \n",
- "144 50 20 \n",
- "2336 50 50 \n",
- "... ... ... \n",
- "1703 0 0 \n",
- "2441 0 0 \n",
- "1054 0 0 \n",
- "1488 0 0 \n",
- "1619 0 0 \n",
- "\n",
- " gross_profit_ratio_volatility operating_safety_margin \\\n",
- "2393 50 0 \n",
- "323 50 0 \n",
- "3238 50 0 \n",
- "144 50 0 \n",
- "2336 50 0 \n",
- "... ... ... \n",
- "1703 50 0 \n",
- "2441 50 0 \n",
- "1054 50 0 \n",
- "1488 50 0 \n",
- "1619 50 0 \n",
- "\n",
- " net_income_ascending operating_net_cash_flow_ascending \n",
- "2393 90 40 \n",
- "323 90 50 \n",
- "3238 90 60 \n",
- "144 90 90 \n",
- "2336 30 30 \n",
- "... ... ... \n",
- "1703 -60 -90 \n",
- "2441 -90 -60 \n",
- "1054 -90 -90 \n",
- "1488 -90 -90 \n",
- "1619 -90 -90 \n",
- "\n",
- "[3384 rows x 12 columns]"
- ],
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " code | \n",
- " name | \n",
- " score | \n",
- " roe_score | \n",
- " roa_score | \n",
- " net_income | \n",
- " assets_turnover_and_cash | \n",
- " collection_cash_period_and_sales_period | \n",
- " gross_profit_ratio_volatility | \n",
- " operating_safety_margin | \n",
- " net_income_ascending | \n",
- " operating_net_cash_flow_ascending | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " | 2393 | \n",
- " 600519.SH | \n",
- " 贵州茅台 | \n",
- " 950 | \n",
- " 500 | \n",
- " 100 | \n",
- " 100 | \n",
- " 50 | \n",
- " 20 | \n",
- " 50 | \n",
- " 0 | \n",
- " 90 | \n",
- " 40 | \n",
- "
\n",
- " \n",
- " | 323 | \n",
- " 000858.SZ | \n",
- " 五粮液 | \n",
- " 910 | \n",
- " 450 | \n",
- " 100 | \n",
- " 100 | \n",
- " 50 | \n",
- " 20 | \n",
- " 50 | \n",
- " 0 | \n",
- " 90 | \n",
- " 50 | \n",
- "
\n",
- " \n",
- " | 3238 | \n",
- " 603688.SH | \n",
- " 石英股份 | \n",
- " 850 | \n",
- " 500 | \n",
- " 100 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " 90 | \n",
- " 60 | \n",
- "
\n",
- " \n",
- " | 144 | \n",
- " 000568.SZ | \n",
- " 泸州老窖 | \n",
- " 850 | \n",
- " 450 | \n",
- " 100 | \n",
- " 0 | \n",
- " 50 | \n",
- " 20 | \n",
- " 50 | \n",
- " 0 | \n",
- " 90 | \n",
- " 90 | \n",
- "
\n",
- " \n",
- " | 2336 | \n",
- " 600438.SH | \n",
- " 通威股份 | \n",
- " 840 | \n",
- " 450 | \n",
- " 80 | \n",
- " 100 | \n",
- " 50 | \n",
- " 50 | \n",
- " 50 | \n",
- " 0 | \n",
- " 30 | \n",
- " 30 | \n",
- "
\n",
- " \n",
- " | ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- "
\n",
- " \n",
- " | 1703 | \n",
- " 300436.SZ | \n",
- " 广生堂 | \n",
- " -100 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " -60 | \n",
- " -90 | \n",
- "
\n",
- " \n",
- " | 2441 | \n",
- " 600579.SH | \n",
- " 克劳斯 | \n",
- " -100 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " -90 | \n",
- " -60 | \n",
- "
\n",
- " \n",
- " | 1054 | \n",
- " 002672.SZ | \n",
- " 东江环保 | \n",
- " -130 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " -90 | \n",
- " -90 | \n",
- "
\n",
- " \n",
- " | 1488 | \n",
- " 300204.SZ | \n",
- " 舒泰神 | \n",
- " -130 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " -90 | \n",
- " -90 | \n",
- "
\n",
- " \n",
- " | 1619 | \n",
- " 300345.SZ | \n",
- " 华民股份 | \n",
- " -130 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 0 | \n",
- " 50 | \n",
- " 0 | \n",
- " -90 | \n",
- " -90 | \n",
- "
\n",
- " \n",
- "
\n",
- "
3384 rows × 12 columns
\n",
- "
"
- ]
- },
- "execution_count": 16,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 16
+ "outputs": [],
+ "execution_count": null
},
{
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-14T14:25:22.482926Z",
- "start_time": "2025-01-14T14:25:22.476830Z"
- }
- },
+ "metadata": {},
"cell_type": "code",
"source": "df[:100][\"code\"]",
"id": "32b5b4778985afaa",
- "outputs": [
- {
- "data": {
- "text/plain": [
- "2393 600519.SH\n",
- "323 000858.SZ\n",
- "3238 603688.SH\n",
- "144 000568.SZ\n",
- "2336 600438.SH\n",
- " ... \n",
- "3318 603871.SH\n",
- "2542 600702.SH\n",
- "1166 002801.SZ\n",
- "1227 002867.SZ\n",
- "1754 300487.SZ\n",
- "Name: code, Length: 100, dtype: object"
- ]
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 17
+ "outputs": [],
+ "execution_count": null
},
{
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-13T03:17:08.882164Z",
- "start_time": "2025-01-13T03:17:08.862820Z"
- }
- },
+ "metadata": {},
"cell_type": "code",
"source": [
"temp_df = finance_df[finance_df[\"code\"] == \"600763.SH\"]\n",
@@ -1599,357 +954,12 @@
"temp_df[[\"year\", \"roe\", \"roa\"]]"
],
"id": "e6d973f4ff98ebef",
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_51974/3287426981.py:2: SettingWithCopyWarning: \n",
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
- "\n",
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
- " df[\"prev_total_stockholder_interest\"] = df[\"total_stockholder_interest\"].shift(1)\n",
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_51974/3287426981.py:3: SettingWithCopyWarning: \n",
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
- "\n",
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
- " df[\"roe\"] = df[\"net_income\"] / ((df[\"prev_total_stockholder_interest\"] + df[\"total_stockholder_interest\"]) / 2)\n",
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_51974/3287426981.py:4: SettingWithCopyWarning: \n",
- "A value is trying to be set on a copy of a slice from a DataFrame\n",
- "\n",
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
- " df.drop(columns=[\"prev_total_stockholder_interest\"], inplace=True)\n",
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_51974/3105409447.py:2: SettingWithCopyWarning: \n",
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
- "\n",
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
- " df[\"prev_total_assets\"] = df[\"total_assets\"].shift(1)\n",
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_51974/3105409447.py:3: SettingWithCopyWarning: \n",
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
- "\n",
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
- " df[\"roa\"] = df[\"net_income\"] / ((df[\"prev_total_assets\"] + df[\"total_assets\"]) / 2)\n",
- "/var/folders/7h/w0cmp4zj6mn9br_6nyj310m40000gn/T/ipykernel_51974/3105409447.py:4: SettingWithCopyWarning: \n",
- "A value is trying to be set on a copy of a slice from a DataFrame\n",
- "\n",
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
- " df.drop(columns=[\"prev_total_assets\"], inplace=True)\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- " year roe roa\n",
- "2979 2014 NaN NaN\n",
- "7615 2015 0.245119 0.182412\n",
- "12121 2016 0.148244 0.101560\n",
- "16405 2017 0.226923 0.147172\n",
- "21964 2018 0.282053 0.182929\n",
- "25657 2019 0.297166 0.211903\n",
- "29113 2020 0.252412 0.190406\n",
- "36313 2021 0.286244 0.196068\n",
- "40855 2022 0.182081 0.121805\n",
- "45977 2023 0.149449 0.103658"
- ],
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " year | \n",
- " roe | \n",
- " roa | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " | 2979 | \n",
- " 2014 | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " | 7615 | \n",
- " 2015 | \n",
- " 0.245119 | \n",
- " 0.182412 | \n",
- "
\n",
- " \n",
- " | 12121 | \n",
- " 2016 | \n",
- " 0.148244 | \n",
- " 0.101560 | \n",
- "
\n",
- " \n",
- " | 16405 | \n",
- " 2017 | \n",
- " 0.226923 | \n",
- " 0.147172 | \n",
- "
\n",
- " \n",
- " | 21964 | \n",
- " 2018 | \n",
- " 0.282053 | \n",
- " 0.182929 | \n",
- "
\n",
- " \n",
- " | 25657 | \n",
- " 2019 | \n",
- " 0.297166 | \n",
- " 0.211903 | \n",
- "
\n",
- " \n",
- " | 29113 | \n",
- " 2020 | \n",
- " 0.252412 | \n",
- " 0.190406 | \n",
- "
\n",
- " \n",
- " | 36313 | \n",
- " 2021 | \n",
- " 0.286244 | \n",
- " 0.196068 | \n",
- "
\n",
- " \n",
- " | 40855 | \n",
- " 2022 | \n",
- " 0.182081 | \n",
- " 0.121805 | \n",
- "
\n",
- " \n",
- " | 45977 | \n",
- " 2023 | \n",
- " 0.149449 | \n",
- " 0.103658 | \n",
- "
\n",
- " \n",
- "
\n",
- "
"
- ]
- },
- "execution_count": 204,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 204
+ "outputs": [],
+ "execution_count": null
},
{
"metadata": {},
"cell_type": "code",
- "outputs": [
- {
- "data": {
- "text/plain": [
- " ts_code end_date roe roa\n",
- "4 600763.SH 20231231 14.0666 13.4808\n",
- "10 600763.SH 20221231 17.7106 15.4075\n",
- "11 600763.SH 20221231 17.7106 15.4075\n",
- "18 600763.SH 20211231 27.9402 24.7367\n",
- "19 600763.SH 20211231 27.9402 24.7367\n",
- "26 600763.SH 20201231 25.0345 24.1350\n",
- "27 600763.SH 20201231 25.0345 24.1350\n",
- "34 600763.SH 20191231 29.8694 27.2723\n",
- "35 600763.SH 20191231 29.8694 27.2723\n",
- "42 600763.SH 20181231 28.7803 23.4500\n",
- "43 600763.SH 20181231 28.7803 23.4500\n",
- "50 600763.SH 20171231 23.9279 18.8885\n",
- "51 600763.SH 20171231 23.9279 18.8885\n",
- "58 600763.SH 20161231 16.6081 13.5829\n",
- "59 600763.SH 20161231 16.6081 13.5829\n",
- "66 600763.SH 20151231 26.5184 22.2861\n",
- "67 600763.SH 20151231 26.5184 22.2861\n",
- "74 600763.SH 20141231 19.1679 20.0538\n",
- "75 600763.SH 20141231 19.1679 20.0538"
- ],
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " ts_code | \n",
- " end_date | \n",
- " roe | \n",
- " roa | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " | 4 | \n",
- " 600763.SH | \n",
- " 20231231 | \n",
- " 14.0666 | \n",
- " 13.4808 | \n",
- "
\n",
- " \n",
- " | 10 | \n",
- " 600763.SH | \n",
- " 20221231 | \n",
- " 17.7106 | \n",
- " 15.4075 | \n",
- "
\n",
- " \n",
- " | 11 | \n",
- " 600763.SH | \n",
- " 20221231 | \n",
- " 17.7106 | \n",
- " 15.4075 | \n",
- "
\n",
- " \n",
- " | 18 | \n",
- " 600763.SH | \n",
- " 20211231 | \n",
- " 27.9402 | \n",
- " 24.7367 | \n",
- "
\n",
- " \n",
- " | 19 | \n",
- " 600763.SH | \n",
- " 20211231 | \n",
- " 27.9402 | \n",
- " 24.7367 | \n",
- "
\n",
- " \n",
- " | 26 | \n",
- " 600763.SH | \n",
- " 20201231 | \n",
- " 25.0345 | \n",
- " 24.1350 | \n",
- "
\n",
- " \n",
- " | 27 | \n",
- " 600763.SH | \n",
- " 20201231 | \n",
- " 25.0345 | \n",
- " 24.1350 | \n",
- "
\n",
- " \n",
- " | 34 | \n",
- " 600763.SH | \n",
- " 20191231 | \n",
- " 29.8694 | \n",
- " 27.2723 | \n",
- "
\n",
- " \n",
- " | 35 | \n",
- " 600763.SH | \n",
- " 20191231 | \n",
- " 29.8694 | \n",
- " 27.2723 | \n",
- "
\n",
- " \n",
- " | 42 | \n",
- " 600763.SH | \n",
- " 20181231 | \n",
- " 28.7803 | \n",
- " 23.4500 | \n",
- "
\n",
- " \n",
- " | 43 | \n",
- " 600763.SH | \n",
- " 20181231 | \n",
- " 28.7803 | \n",
- " 23.4500 | \n",
- "
\n",
- " \n",
- " | 50 | \n",
- " 600763.SH | \n",
- " 20171231 | \n",
- " 23.9279 | \n",
- " 18.8885 | \n",
- "
\n",
- " \n",
- " | 51 | \n",
- " 600763.SH | \n",
- " 20171231 | \n",
- " 23.9279 | \n",
- " 18.8885 | \n",
- "
\n",
- " \n",
- " | 58 | \n",
- " 600763.SH | \n",
- " 20161231 | \n",
- " 16.6081 | \n",
- " 13.5829 | \n",
- "
\n",
- " \n",
- " | 59 | \n",
- " 600763.SH | \n",
- " 20161231 | \n",
- " 16.6081 | \n",
- " 13.5829 | \n",
- "
\n",
- " \n",
- " | 66 | \n",
- " 600763.SH | \n",
- " 20151231 | \n",
- " 26.5184 | \n",
- " 22.2861 | \n",
- "
\n",
- " \n",
- " | 67 | \n",
- " 600763.SH | \n",
- " 20151231 | \n",
- " 26.5184 | \n",
- " 22.2861 | \n",
- "
\n",
- " \n",
- " | 74 | \n",
- " 600763.SH | \n",
- " 20141231 | \n",
- " 19.1679 | \n",
- " 20.0538 | \n",
- "
\n",
- " \n",
- " | 75 | \n",
- " 600763.SH | \n",
- " 20141231 | \n",
- " 19.1679 | \n",
- " 20.0538 | \n",
- "
\n",
- " \n",
- "
\n",
- "
"
- ]
- },
- "execution_count": 206,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "execution_count": 206,
"source": [
"temp_df = ts_pro.fina_indicator(\n",
" ts_code=\"600763.SH\", start_date=\"20140101\", end_date=\"20241231\",\n",
@@ -1960,7 +970,9 @@
"# temp_df = temp_df.drop_duplicates(subset=[\"end_date\"], keep=\"last\")\n",
"temp_df"
],
- "id": "b220252765677c76"
+ "id": "b220252765677c76",
+ "outputs": [],
+ "execution_count": null
}
],
"metadata": {