diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/selector.py b/selector.py
deleted file mode 100644
index edef7f9..0000000
--- a/selector.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import pandas as pd
-
-
-class Selector:
- def select(self, codes: [str], df: pd.DataFrame) -> [str]:
- return codes
-
-
-class Score:
- def score(self, codes: [str], df: pd.DataFrame) -> [(str, int)]:
- return list(map(lambda code: (code, 0), codes))
-
-
-class PeriodSelector(Selector):
- def __init__(self, period: int = 5):
- self.__period = period
-
- def select(self, codes: [str], df: pd.DataFrame) -> [str]:
- size_df = df.groupby("code").size()
- return list(filter(lambda code: size_df[code] > self.__period, codes))
diff --git a/strategy.py b/strategy.py
new file mode 100644
index 0000000..38572b7
--- /dev/null
+++ b/strategy.py
@@ -0,0 +1,44 @@
+import pandas as pd
+
+
+class Selector:
+ def select(self, codes: [str], df: pd.DataFrame) -> [str]:
+ return codes
+
+
+class Strategy:
+ def __init__(self, selectors: [Selector]):
+ self.selectors = selectors
+
+ def select(self, codes: [str], df: pd.DataFrame) -> [str]:
+ return list(map(lambda code: self.selectors.select(code, df), codes))
+
+
+class PeriodSelector(Selector):
+ def __init__(self, period: int = 5):
+ self.__period = period
+
+ def select(self, codes: [str], df: pd.DataFrame) -> [str]:
+ size_df = df.groupby("code").size()
+ return list(filter(lambda code: size_df[code] > self.__period, codes))
+
+
+class PyramidSelector(Selector):
+ def select(self, codes: [str], df: pd.DataFrame) -> [str]:
+ target_df = df[df["code"].isin(codes)]
+ target_df["score"] = 0
+ group_df = target_df.groupby("code")
+
+ target_df["prev_total_stockholder_interest"] = group_df["total_stockholder_interest"].shift(1)
+ target_df["roe"] = target_df["net_income"] / ((target_df["prev_total_stockholder_interest"] + target_df["total_stockholder_interest"]) / 2)
+ target_df["average_roe"] = target_df["roe"].mean()
+ target_df[target_df["average_roe"] >= 35] = target_df["score"] + 550
+ target_df[(target_df["average_roe"] < 35) & (target_df["average_roe"] >= 30)] = target_df["score"] + 500
+ target_df[(target_df["average_roe"] < 30) & (target_df["average_roe"] >= 25)] = target_df["score"] + 450
+ target_df[(target_df["average_roe"] < 25) & (target_df["average_roe"] >= 15)] = target_df["score"] + 300
+ target_df[(target_df["average_roe"] < 15) & (target_df["average_roe"] >= 10)] = target_df["score"] + 250
+
+ target_df["prev_total_assets"] = group_df["total_assets"].shift(1)
+ target_df["roa"] = target_df["net_income"] / ((target_df["prev_total_assets"] + target_df["total_assets"]) / 2)
+
+ return super().select(codes, df)
diff --git a/财报筛选/选股测试.ipynb b/财报筛选/选股测试.ipynb
index a1ae465..9dcc632 100644
--- a/财报筛选/选股测试.ipynb
+++ b/财报筛选/选股测试.ipynb
@@ -67,7 +67,7 @@
},
"cell_type": "code",
"source": [
- "from selector import PeriodSelector\n",
+ "from strategy import PeriodSelector\n",
"\n",
"filter_df = finance_df[(2010 < finance_df[\"year\"]) & (finance_df[\"year\"] < 2025)]\n",
"codes = filter_df[\"code\"].unique().tolist()\n",
diff --git a/财报筛选/金字塔选股.ipynb b/财报筛选/金字塔选股.ipynb
index 68f1bd4..0bd1be2 100644
--- a/财报筛选/金字塔选股.ipynb
+++ b/财报筛选/金字塔选股.ipynb
@@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
- "end_time": "2025-01-14T14:10:53.801418Z",
- "start_time": "2025-01-14T14:10:53.532671Z"
+ "end_time": "2025-01-17T02:07:55.001963Z",
+ "start_time": "2025-01-17T02:07:54.772694Z"
}
},
"source": [
@@ -22,8 +22,103 @@
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-01-14T14:10:56.411909Z",
- "start_time": "2025-01-14T14:10:55.020264Z"
+ "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"
}
},
"cell_type": "code",
@@ -72,46 +167,192 @@
" \"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)"
],
"id": "68b2debc14502fd5",
"outputs": [],
- "execution_count": 3
+ "execution_count": 148
+ },
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": "过滤上市时间大于5年的企业,由于计算很多数值需要与前一年比,所以实际上需要的是上市时间至少6年的企业",
+ "id": "3052b8c4442f3643"
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-01-14T14:22:17.070395Z",
- "start_time": "2025-01-14T14:22:17.053180Z"
+ "end_time": "2025-01-17T10:11:57.531470Z",
+ "start_time": "2025-01-17T10:11:57.287352Z"
}
},
"cell_type": "code",
- "source": "finance_df[finance_df[\"code\"] == \"600763.SH\"][[\"year\", \"net_income\"]]",
- "id": "f0e8942b3403348c",
+ "source": "finance_df = finance_df.groupby(\"code\").filter(lambda x: len(x) > 6)",
+ "id": "4293bd93ea8f9ed",
+ "outputs": [],
+ "execution_count": 149
+ },
+ {
+ "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-17T10:12:05.859920Z",
+ "start_time": "2025-01-17T10:12:00.853021Z"
+ }
+ },
+ "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.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",
+ "\n",
+ "finance_df[finance_df[\"code\"] == '000002.SZ']"
+ ],
+ "id": "f050d33c4a0cd720",
"outputs": [
+ {
+ "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"
+ ]
+ },
{
"data": {
"text/plain": [
- " year net_income\n",
- "1808 2005 3.467468e+06\n",
- "3228 2006 1.212677e+06\n",
- "4784 2007 1.015147e+07\n",
- "8425 2008 1.466373e+07\n",
- "9811 2009 2.172666e+07\n",
- "12426 2010 4.982651e+07\n",
- "17669 2011 7.169039e+07\n",
- "19876 2012 9.554584e+07\n",
- "25082 2013 1.024329e+08\n",
- "28480 2014 1.138340e+08\n",
- "33116 2015 1.936414e+08\n",
- "37622 2016 1.328421e+08\n",
- "41906 2017 2.266875e+08\n",
- "47465 2018 3.592014e+08\n",
- "51158 2019 5.077704e+08\n",
- "54614 2020 5.449616e+08\n",
- "61814 2021 7.861501e+08\n",
- "66356 2022 6.156781e+08\n",
- "71478 2023 5.784234e+08"
+ " 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",
+ "\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",
+ "\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",
+ "\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",
+ "\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 "
],
"text/html": [
"\n",
@@ -132,223 +373,487 @@
" \n",
" \n",
" | \n",
+ " code | \n",
" year | \n",
+ " total_stockholder_interest | \n",
" net_income | \n",
+ " total_assets | \n",
+ " total_revenue | \n",
+ " inventories | \n",
+ " 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",
- " | 1808 | \n",
+ " 1945 | \n",
+ " 000002.SZ | \n",
" 2005 | \n",
- " 3.467468e+06 | \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",
- " | 3228 | \n",
+ " 3432 | \n",
+ " 000002.SZ | \n",
" 2006 | \n",
- " 1.212677e+06 | \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",
- " | 4784 | \n",
+ " 5449 | \n",
+ " 000002.SZ | \n",
" 2007 | \n",
- " 1.015147e+07 | \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",
- " | 8425 | \n",
+ " 7921 | \n",
+ " 000002.SZ | \n",
" 2008 | \n",
- " 1.466373e+07 | \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",
- " | 9811 | \n",
+ " 10605 | \n",
+ " 000002.SZ | \n",
" 2009 | \n",
- " 2.172666e+07 | \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",
- " | 12426 | \n",
+ " 13934 | \n",
+ " 000002.SZ | \n",
" 2010 | \n",
- " 4.982651e+07 | \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",
- " | 17669 | \n",
+ " 17289 | \n",
+ " 000002.SZ | \n",
" 2011 | \n",
- " 7.169039e+07 | \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",
- " | 19876 | \n",
+ " 20376 | \n",
+ " 000002.SZ | \n",
" 2012 | \n",
- " 9.554584e+07 | \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",
- " | 25082 | \n",
+ " 25215 | \n",
+ " 000002.SZ | \n",
" 2013 | \n",
- " 1.024329e+08 | \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",
- " | 28480 | \n",
+ " 29387 | \n",
+ " 000002.SZ | \n",
" 2014 | \n",
- " 1.138340e+08 | \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",
- " | 33116 | \n",
+ " 33753 | \n",
+ " 000002.SZ | \n",
" 2015 | \n",
- " 1.936414e+08 | \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",
- " | 37622 | \n",
+ " 37463 | \n",
+ " 000002.SZ | \n",
" 2016 | \n",
- " 1.328421e+08 | \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",
- " | 41906 | \n",
+ " 42678 | \n",
+ " 000002.SZ | \n",
" 2017 | \n",
- " 2.266875e+08 | \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",
- " | 47465 | \n",
+ " 47756 | \n",
+ " 000002.SZ | \n",
" 2018 | \n",
- " 3.592014e+08 | \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",
- " | 51158 | \n",
+ " 52944 | \n",
+ " 000002.SZ | \n",
" 2019 | \n",
- " 5.077704e+08 | \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",
- " | 54614 | \n",
+ " 57414 | \n",
+ " 000002.SZ | \n",
" 2020 | \n",
- " 5.449616e+08 | \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",
- " | 61814 | \n",
+ " 59180 | \n",
+ " 000002.SZ | \n",
" 2021 | \n",
- " 7.861501e+08 | \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",
- " | 66356 | \n",
+ " 62929 | \n",
+ " 000002.SZ | \n",
" 2022 | \n",
- " 6.156781e+08 | \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",
- " | 71478 | \n",
+ " 68422 | \n",
+ " 000002.SZ | \n",
" 2023 | \n",
- " 5.784234e+08 | \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": 4,
+ "execution_count": 150,
"metadata": {},
"output_type": "execute_result"
}
],
- "execution_count": 4
- },
- {
- "metadata": {},
- "cell_type": "markdown",
- "source": "过滤上市时间大于5年的企业,由于计算很多数值需要与前一年比,所以实际上需要的是上市时间至少6年的企业",
- "id": "3052b8c4442f3643"
+ "execution_count": 150
},
{
"metadata": {
"ExecuteTime": {
- "end_time": "2025-01-14T14:22:57.782337Z",
- "start_time": "2025-01-14T14:22:57.774714Z"
+ "end_time": "2025-01-17T10:19:25.031141Z",
+ "start_time": "2025-01-17T10:19:25.020325Z"
}
},
"cell_type": "code",
"source": [
- "from datetime import datetime\n",
- "\n",
- "select_df = stock_df[[\"ts_code\", \"list_date\"]]\n",
- "select_df.loc[:, \"list_date\"] = pd.to_datetime(select_df[\"list_date\"], format=\"%Y%m%d\").dt.year\n",
- "select_df = select_df[select_df[\"list_date\"] < datetime.now().year - 6]\n",
- "codes = select_df[\"ts_code\"].tolist()\n",
- "codes = map(lambda x: [x, stock_df[stock_df[\"ts_code\"] == x][\"name\"].values[0], 0], codes)"
+ "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": "4293bd93ea8f9ed",
- "outputs": [],
- "execution_count": 5
- },
- {
- "metadata": {
- "ExecuteTime": {
- "end_time": "2025-01-14T14:22:59.917536Z",
- "start_time": "2025-01-14T14:22:59.914056Z"
+ "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",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 1 | \n",
+ " 2 | \n",
+ " 0 | \n",
+ " False | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 1 | \n",
+ " 3 | \n",
+ " 0 | \n",
+ " False | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 1 | \n",
+ " -4 | \n",
+ " 0 | \n",
+ " True | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ]
+ },
+ "execution_count": 165,
+ "metadata": {},
+ "output_type": "execute_result"
}
- },
- "cell_type": "code",
- "source": [
- "def add_score(code_list, score):\n",
- " code_list[2] = code_list[2] + score\n",
- " code_list.append(score)\n",
- " return code_list"
],
- "id": "fa22f7c620511f0a",
- "outputs": [],
- "execution_count": 6
- },
- {
- "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-14T14:23:11.032339Z",
- "start_time": "2025-01-14T14:23:02.481495Z"
- }
- },
- "cell_type": "code",
- "source": [
- "def cal_roe(df):\n",
- " df[\"prev_total_stockholder_interest\"] = df[\"total_stockholder_interest\"].shift(1)\n",
- " df[\"roe\"] = df[\"net_income\"] / ((df[\"prev_total_stockholder_interest\"] + df[\"total_stockholder_interest\"]) / 2)\n",
- " df.drop(columns=[\"prev_total_stockholder_interest\"], inplace=True)\n",
- "\n",
- "\n",
- "def score_by_roe(code):\n",
- " temp_df = finance_df[finance_df[\"code\"] == code].copy()\n",
- " cal_roe(temp_df)\n",
- "\n",
- " if any(roe < 0 for roe in temp_df[\"roe\"]):\n",
- " return 0\n",
- "\n",
- " average_roe = temp_df.nlargest(5, \"year\")[\"roe\"].mean() * 100\n",
- "\n",
- " if average_roe >= 35:\n",
- " return 550\n",
- " elif average_roe >= 30:\n",
- " return 500\n",
- " elif average_roe >= 25:\n",
- " return 450\n",
- " elif average_roe >= 15:\n",
- " return 300\n",
- " elif average_roe >= 10:\n",
- " return 250\n",
- " else:\n",
- " return 0\n",
- "\n",
- "\n",
- "codes = list(map(lambda x: add_score(x, score_by_roe(x[0])), codes))"
- ],
- "id": "f050d33c4a0cd720",
- "outputs": [],
- "execution_count": 7
+ "execution_count": 165
},
{
"metadata": {},
@@ -763,11 +1268,13 @@
},
"cell_type": "code",
"source": [
- "df = pd.DataFrame(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",
+ "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",
+ ")\n",
"df.sort_values(by=\"score\", ascending=False, inplace=True)\n",
"df"
],
@@ -1444,8 +1951,10 @@
],
"execution_count": 206,
"source": [
- "temp_df = ts_pro.fina_indicator(ts_code=\"600763.SH\", start_date=\"20140101\", end_date=\"20241231\",\n",
- " fields=\"ts_code,end_date,roe,roa\")\n",
+ "temp_df = ts_pro.fina_indicator(\n",
+ " ts_code=\"600763.SH\", start_date=\"20140101\", end_date=\"20241231\",\n",
+ " fields=\"ts_code,end_date,roe,roa\"\n",
+ ")\n",
"temp_df = temp_df[temp_df[\"end_date\"].str.endswith(\"1231\")]\n",
"# temp_df[\"end_date\"] = temp_df[\"end_date\"].str[:4]\n",
"# temp_df = temp_df.drop_duplicates(subset=[\"end_date\"], keep=\"last\")\n",