完成回测的基本计算
This commit is contained in:
912
backtest.ipynb
912
backtest.ipynb
@@ -2,262 +2,260 @@
|
||||
"cells": [
|
||||
{
|
||||
"metadata": {
|
||||
"SqlCellData": {
|
||||
"data_source_name": "leopard_dev@81.71.3.24",
|
||||
"variableName$1": "dailies_df"
|
||||
},
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-19T10:00:35.820002Z",
|
||||
"start_time": "2026-01-19T10:00:34.354216Z"
|
||||
"end_time": "2026-01-20T02:26:30.134545Z",
|
||||
"start_time": "2026-01-20T02:26:22.978651Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"%%sql\n",
|
||||
"select trade_date, open * factor as Open, close * factor as Close, high * factor as High, low * factor as Low, volume as Volume, coalesce(factor, 1.0) as factor\n",
|
||||
"from leopard_daily daily\n",
|
||||
" left join leopard_stock stock on stock.id = daily.stock_id\n",
|
||||
"where stock.code = '000001.SZ'\n",
|
||||
" and daily.trade_date between '2025-01-01 00:00:00' and '2025-12-31 23:59:59'\n",
|
||||
"order by daily.trade_date"
|
||||
],
|
||||
"id": "93e66142c88e4d2f",
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" trade_date open close high low \\\n",
|
||||
"0 2025-01-02 1498.907493 1460.572263 1504.018857 1455.460899 \n",
|
||||
"1 2025-01-03 1461.850104 1454.183058 1474.628514 1451.627376 \n",
|
||||
"2 2025-01-06 1454.183058 1461.850104 1466.961468 1433.737602 \n",
|
||||
"3 2025-01-07 1459.294422 1470.794991 1473.350673 1452.905217 \n",
|
||||
"4 2025-01-08 1469.517150 1469.517150 1486.129083 1456.738740 \n",
|
||||
".. ... ... ... ... ... \n",
|
||||
"183 2025-10-09 1493.155774 1502.380920 1503.698798 1485.248506 \n",
|
||||
"184 2025-10-10 1498.427286 1506.334554 1514.241822 1497.109408 \n",
|
||||
"185 2025-10-13 1491.837896 1502.380920 1510.288188 1486.566384 \n",
|
||||
"186 2025-10-14 1501.063042 1524.784846 1528.738480 1497.109408 \n",
|
||||
"187 2025-10-15 1526.130396 1534.205160 1536.896748 1515.364044 \n",
|
||||
"\n",
|
||||
" volume factor \n",
|
||||
"0 1819596.99 127.7841 \n",
|
||||
"1 1154680.44 127.7841 \n",
|
||||
"2 1085536.30 127.7841 \n",
|
||||
"3 747862.88 127.7841 \n",
|
||||
"4 1062386.01 127.7841 \n",
|
||||
".. ... ... \n",
|
||||
"183 1047469.06 131.7878 \n",
|
||||
"184 1087947.75 131.7878 \n",
|
||||
"185 1168801.73 131.7878 \n",
|
||||
"186 1843428.36 131.7878 \n",
|
||||
"187 1271061.03 134.5794 \n",
|
||||
"\n",
|
||||
"[188 rows x 7 columns]"
|
||||
],
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>trade_date</th>\n",
|
||||
" <th>open</th>\n",
|
||||
" <th>close</th>\n",
|
||||
" <th>high</th>\n",
|
||||
" <th>low</th>\n",
|
||||
" <th>volume</th>\n",
|
||||
" <th>factor</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>2025-01-02</td>\n",
|
||||
" <td>1498.907493</td>\n",
|
||||
" <td>1460.572263</td>\n",
|
||||
" <td>1504.018857</td>\n",
|
||||
" <td>1455.460899</td>\n",
|
||||
" <td>1819596.99</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>2025-01-03</td>\n",
|
||||
" <td>1461.850104</td>\n",
|
||||
" <td>1454.183058</td>\n",
|
||||
" <td>1474.628514</td>\n",
|
||||
" <td>1451.627376</td>\n",
|
||||
" <td>1154680.44</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>2025-01-06</td>\n",
|
||||
" <td>1454.183058</td>\n",
|
||||
" <td>1461.850104</td>\n",
|
||||
" <td>1466.961468</td>\n",
|
||||
" <td>1433.737602</td>\n",
|
||||
" <td>1085536.30</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>2025-01-07</td>\n",
|
||||
" <td>1459.294422</td>\n",
|
||||
" <td>1470.794991</td>\n",
|
||||
" <td>1473.350673</td>\n",
|
||||
" <td>1452.905217</td>\n",
|
||||
" <td>747862.88</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>2025-01-08</td>\n",
|
||||
" <td>1469.517150</td>\n",
|
||||
" <td>1469.517150</td>\n",
|
||||
" <td>1486.129083</td>\n",
|
||||
" <td>1456.738740</td>\n",
|
||||
" <td>1062386.01</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>...</th>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>183</th>\n",
|
||||
" <td>2025-10-09</td>\n",
|
||||
" <td>1493.155774</td>\n",
|
||||
" <td>1502.380920</td>\n",
|
||||
" <td>1503.698798</td>\n",
|
||||
" <td>1485.248506</td>\n",
|
||||
" <td>1047469.06</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>184</th>\n",
|
||||
" <td>2025-10-10</td>\n",
|
||||
" <td>1498.427286</td>\n",
|
||||
" <td>1506.334554</td>\n",
|
||||
" <td>1514.241822</td>\n",
|
||||
" <td>1497.109408</td>\n",
|
||||
" <td>1087947.75</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>185</th>\n",
|
||||
" <td>2025-10-13</td>\n",
|
||||
" <td>1491.837896</td>\n",
|
||||
" <td>1502.380920</td>\n",
|
||||
" <td>1510.288188</td>\n",
|
||||
" <td>1486.566384</td>\n",
|
||||
" <td>1168801.73</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>186</th>\n",
|
||||
" <td>2025-10-14</td>\n",
|
||||
" <td>1501.063042</td>\n",
|
||||
" <td>1524.784846</td>\n",
|
||||
" <td>1528.738480</td>\n",
|
||||
" <td>1497.109408</td>\n",
|
||||
" <td>1843428.36</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>187</th>\n",
|
||||
" <td>2025-10-15</td>\n",
|
||||
" <td>1526.130396</td>\n",
|
||||
" <td>1534.205160</td>\n",
|
||||
" <td>1536.896748</td>\n",
|
||||
" <td>1515.364044</td>\n",
|
||||
" <td>1271061.03</td>\n",
|
||||
" <td>134.5794</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"<p>188 rows × 7 columns</p>\n",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"execution_count": 87,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 87
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-20T02:26:30.368092Z",
|
||||
"start_time": "2026-01-20T02:26:30.241161Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"host = '81.71.3.24'\n",
|
||||
"port = 6785\n",
|
||||
"database = 'leopard_dev'\n",
|
||||
"username = 'leopard'\n",
|
||||
"password = '9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X'"
|
||||
],
|
||||
"id": "d815a3591c4f9463",
|
||||
"outputs": [],
|
||||
"execution_count": 2
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "initial_id",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-19T10:00:42.739695Z",
|
||||
"start_time": "2026-01-19T10:00:35.820726Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"import psycopg2\n",
|
||||
"\n",
|
||||
"dailies_df = pd.DataFrame()\n",
|
||||
"\n",
|
||||
"with psycopg2.connect(host=host, port=port, database=database, user=username, password=password) as connection:\n",
|
||||
" with connection.cursor() as cursor:\n",
|
||||
" # language=PostgreSQL\n",
|
||||
" cursor.execute(\n",
|
||||
" \"\"\"select trade_date, open, close, high, low, factor\n",
|
||||
"from leopard_daily daily\n",
|
||||
" left join leopard_stock stock on stock.id = daily.stock_id\n",
|
||||
"where stock.code = '000001.SZ'\n",
|
||||
" and daily.trade_date between '2025-01-01 00:00:00' and '2025-12-31 23:59:59'\n",
|
||||
"order by daily.trade_date\"\"\"\n",
|
||||
"dailies_df.rename(\n",
|
||||
" columns={'open': 'Open', 'close': 'Close', 'high': 'High', 'low': 'Low', 'volume': 'Volume'}, inplace=True\n",
|
||||
")\n",
|
||||
" rows = cursor.fetchall()\n",
|
||||
"\n",
|
||||
" dailies_df = pd.DataFrame.from_records(rows, columns=['trade_date', 'open', 'close', 'high', 'low', 'factor'])\n",
|
||||
"\n",
|
||||
"dailies_df['trade_date'] = pd.to_datetime(dailies_df['trade_date'], format='%Y-%m-%d')\n",
|
||||
"dailies_df.set_index('trade_date', inplace=True)\n",
|
||||
"dailies_df"
|
||||
],
|
||||
"id": "c0ed078ffd5b57fd",
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" trade_date open close high low factor\n",
|
||||
"0 2025-01-02 11.73 11.43 11.77 11.39 127.7841\n",
|
||||
"1 2025-01-03 11.44 11.38 11.54 11.36 127.7841\n",
|
||||
"2 2025-01-06 11.38 11.44 11.48 11.22 127.7841\n",
|
||||
"3 2025-01-07 11.42 11.51 11.53 11.37 127.7841\n",
|
||||
"4 2025-01-08 11.50 11.50 11.63 11.40 127.7841\n",
|
||||
".. ... ... ... ... ... ...\n",
|
||||
"183 2025-10-09 11.33 11.40 11.41 11.27 131.7878\n",
|
||||
"184 2025-10-10 11.37 11.43 11.49 11.36 131.7878\n",
|
||||
"185 2025-10-13 11.32 11.40 11.46 11.28 131.7878\n",
|
||||
"186 2025-10-14 11.39 11.57 11.60 11.36 131.7878\n",
|
||||
"187 2025-10-15 11.34 11.40 11.42 11.26 134.5794\n",
|
||||
"\n",
|
||||
"[188 rows x 6 columns]"
|
||||
],
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>trade_date</th>\n",
|
||||
" <th>open</th>\n",
|
||||
" <th>close</th>\n",
|
||||
" <th>high</th>\n",
|
||||
" <th>low</th>\n",
|
||||
" <th>factor</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>2025-01-02</td>\n",
|
||||
" <td>11.73</td>\n",
|
||||
" <td>11.43</td>\n",
|
||||
" <td>11.77</td>\n",
|
||||
" <td>11.39</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>2025-01-03</td>\n",
|
||||
" <td>11.44</td>\n",
|
||||
" <td>11.38</td>\n",
|
||||
" <td>11.54</td>\n",
|
||||
" <td>11.36</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>2025-01-06</td>\n",
|
||||
" <td>11.38</td>\n",
|
||||
" <td>11.44</td>\n",
|
||||
" <td>11.48</td>\n",
|
||||
" <td>11.22</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>2025-01-07</td>\n",
|
||||
" <td>11.42</td>\n",
|
||||
" <td>11.51</td>\n",
|
||||
" <td>11.53</td>\n",
|
||||
" <td>11.37</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>2025-01-08</td>\n",
|
||||
" <td>11.50</td>\n",
|
||||
" <td>11.50</td>\n",
|
||||
" <td>11.63</td>\n",
|
||||
" <td>11.40</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>...</th>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>183</th>\n",
|
||||
" <td>2025-10-09</td>\n",
|
||||
" <td>11.33</td>\n",
|
||||
" <td>11.40</td>\n",
|
||||
" <td>11.41</td>\n",
|
||||
" <td>11.27</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>184</th>\n",
|
||||
" <td>2025-10-10</td>\n",
|
||||
" <td>11.37</td>\n",
|
||||
" <td>11.43</td>\n",
|
||||
" <td>11.49</td>\n",
|
||||
" <td>11.36</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>185</th>\n",
|
||||
" <td>2025-10-13</td>\n",
|
||||
" <td>11.32</td>\n",
|
||||
" <td>11.40</td>\n",
|
||||
" <td>11.46</td>\n",
|
||||
" <td>11.28</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>186</th>\n",
|
||||
" <td>2025-10-14</td>\n",
|
||||
" <td>11.39</td>\n",
|
||||
" <td>11.57</td>\n",
|
||||
" <td>11.60</td>\n",
|
||||
" <td>11.36</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>187</th>\n",
|
||||
" <td>2025-10-15</td>\n",
|
||||
" <td>11.34</td>\n",
|
||||
" <td>11.40</td>\n",
|
||||
" <td>11.42</td>\n",
|
||||
" <td>11.26</td>\n",
|
||||
" <td>134.5794</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"<p>188 rows × 6 columns</p>\n",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 3
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-19T10:01:46.133661Z",
|
||||
"start_time": "2026-01-19T10:01:46.044719Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"dailies_df['factor'] = dailies_df['factor'].fillna(1.0)\n",
|
||||
"dailies_df['open'] = dailies_df['open'] * dailies_df['factor']\n",
|
||||
"dailies_df['close'] = dailies_df['close'] * dailies_df['factor']\n",
|
||||
"dailies_df['high'] = dailies_df['high'] * dailies_df['factor']\n",
|
||||
"dailies_df['low'] = dailies_df['low'] * dailies_df['factor']\n",
|
||||
"dailies_df"
|
||||
],
|
||||
"id": "29226cf1c6fe9f94",
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" trade_date open close high low \\\n",
|
||||
"0 2025-01-02 191536.544976 186637.912112 192189.696025 185984.761064 \n",
|
||||
"1 2025-01-03 186801.199875 185821.473302 188434.077496 185494.897778 \n",
|
||||
"2 2025-01-06 185821.473302 186801.199875 187454.350923 183208.869108 \n",
|
||||
"3 2025-01-07 186474.624350 187944.214209 188270.789734 185658.185540 \n",
|
||||
"4 2025-01-08 187780.926447 187780.926447 189903.667355 186148.048826 \n",
|
||||
".. ... ... ... ... ... \n",
|
||||
"183 2025-10-09 196779.714513 197995.476209 198169.156451 195737.633059 \n",
|
||||
"184 2025-10-10 197474.435482 198516.516936 199558.598389 197300.755240 \n",
|
||||
"185 2025-10-13 196606.034270 197995.476209 199037.557663 195911.313301 \n",
|
||||
"186 2025-10-14 197821.795966 200948.040328 201469.081055 197300.755240 \n",
|
||||
"187 2025-10-15 205385.713015 206472.409910 206834.642208 203936.783823 \n",
|
||||
" Open Close High Low Volume \\\n",
|
||||
"trade_date \n",
|
||||
"2025-01-02 1498.907493 1460.572263 1504.018857 1455.460899 1819596.99 \n",
|
||||
"2025-01-03 1461.850104 1454.183058 1474.628514 1451.627376 1154680.44 \n",
|
||||
"2025-01-06 1454.183058 1461.850104 1466.961468 1433.737602 1085536.30 \n",
|
||||
"2025-01-07 1459.294422 1470.794991 1473.350673 1452.905217 747862.88 \n",
|
||||
"2025-01-08 1469.517150 1469.517150 1486.129083 1456.738740 1062386.01 \n",
|
||||
"... ... ... ... ... ... \n",
|
||||
"2025-10-09 1493.155774 1502.380920 1503.698798 1485.248506 1047469.06 \n",
|
||||
"2025-10-10 1498.427286 1506.334554 1514.241822 1497.109408 1087947.75 \n",
|
||||
"2025-10-13 1491.837896 1502.380920 1510.288188 1486.566384 1168801.73 \n",
|
||||
"2025-10-14 1501.063042 1524.784846 1528.738480 1497.109408 1843428.36 \n",
|
||||
"2025-10-15 1526.130396 1534.205160 1536.896748 1515.364044 1271061.03 \n",
|
||||
"\n",
|
||||
" factor \n",
|
||||
"0 127.7841 \n",
|
||||
"1 127.7841 \n",
|
||||
"2 127.7841 \n",
|
||||
"3 127.7841 \n",
|
||||
"4 127.7841 \n",
|
||||
".. ... \n",
|
||||
"183 131.7878 \n",
|
||||
"184 131.7878 \n",
|
||||
"185 131.7878 \n",
|
||||
"186 131.7878 \n",
|
||||
"187 134.5794 \n",
|
||||
"trade_date \n",
|
||||
"2025-01-02 127.7841 \n",
|
||||
"2025-01-03 127.7841 \n",
|
||||
"2025-01-06 127.7841 \n",
|
||||
"2025-01-07 127.7841 \n",
|
||||
"2025-01-08 127.7841 \n",
|
||||
"... ... \n",
|
||||
"2025-10-09 131.7878 \n",
|
||||
"2025-10-10 131.7878 \n",
|
||||
"2025-10-13 131.7878 \n",
|
||||
"2025-10-14 131.7878 \n",
|
||||
"2025-10-15 134.5794 \n",
|
||||
"\n",
|
||||
"[188 rows x 6 columns]"
|
||||
],
|
||||
@@ -280,58 +278,67 @@
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>trade_date</th>\n",
|
||||
" <th>open</th>\n",
|
||||
" <th>close</th>\n",
|
||||
" <th>high</th>\n",
|
||||
" <th>low</th>\n",
|
||||
" <th>Open</th>\n",
|
||||
" <th>Close</th>\n",
|
||||
" <th>High</th>\n",
|
||||
" <th>Low</th>\n",
|
||||
" <th>Volume</th>\n",
|
||||
" <th>factor</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>trade_date</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>2025-01-02</td>\n",
|
||||
" <td>191536.544976</td>\n",
|
||||
" <td>186637.912112</td>\n",
|
||||
" <td>192189.696025</td>\n",
|
||||
" <td>185984.761064</td>\n",
|
||||
" <th>2025-01-02</th>\n",
|
||||
" <td>1498.907493</td>\n",
|
||||
" <td>1460.572263</td>\n",
|
||||
" <td>1504.018857</td>\n",
|
||||
" <td>1455.460899</td>\n",
|
||||
" <td>1819596.99</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>2025-01-03</td>\n",
|
||||
" <td>186801.199875</td>\n",
|
||||
" <td>185821.473302</td>\n",
|
||||
" <td>188434.077496</td>\n",
|
||||
" <td>185494.897778</td>\n",
|
||||
" <th>2025-01-03</th>\n",
|
||||
" <td>1461.850104</td>\n",
|
||||
" <td>1454.183058</td>\n",
|
||||
" <td>1474.628514</td>\n",
|
||||
" <td>1451.627376</td>\n",
|
||||
" <td>1154680.44</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>2025-01-06</td>\n",
|
||||
" <td>185821.473302</td>\n",
|
||||
" <td>186801.199875</td>\n",
|
||||
" <td>187454.350923</td>\n",
|
||||
" <td>183208.869108</td>\n",
|
||||
" <th>2025-01-06</th>\n",
|
||||
" <td>1454.183058</td>\n",
|
||||
" <td>1461.850104</td>\n",
|
||||
" <td>1466.961468</td>\n",
|
||||
" <td>1433.737602</td>\n",
|
||||
" <td>1085536.30</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>2025-01-07</td>\n",
|
||||
" <td>186474.624350</td>\n",
|
||||
" <td>187944.214209</td>\n",
|
||||
" <td>188270.789734</td>\n",
|
||||
" <td>185658.185540</td>\n",
|
||||
" <th>2025-01-07</th>\n",
|
||||
" <td>1459.294422</td>\n",
|
||||
" <td>1470.794991</td>\n",
|
||||
" <td>1473.350673</td>\n",
|
||||
" <td>1452.905217</td>\n",
|
||||
" <td>747862.88</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>2025-01-08</td>\n",
|
||||
" <td>187780.926447</td>\n",
|
||||
" <td>187780.926447</td>\n",
|
||||
" <td>189903.667355</td>\n",
|
||||
" <td>186148.048826</td>\n",
|
||||
" <th>2025-01-08</th>\n",
|
||||
" <td>1469.517150</td>\n",
|
||||
" <td>1469.517150</td>\n",
|
||||
" <td>1486.129083</td>\n",
|
||||
" <td>1456.738740</td>\n",
|
||||
" <td>1062386.01</td>\n",
|
||||
" <td>127.7841</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
@@ -344,48 +351,48 @@
|
||||
" <td>...</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>183</th>\n",
|
||||
" <td>2025-10-09</td>\n",
|
||||
" <td>196779.714513</td>\n",
|
||||
" <td>197995.476209</td>\n",
|
||||
" <td>198169.156451</td>\n",
|
||||
" <td>195737.633059</td>\n",
|
||||
" <th>2025-10-09</th>\n",
|
||||
" <td>1493.155774</td>\n",
|
||||
" <td>1502.380920</td>\n",
|
||||
" <td>1503.698798</td>\n",
|
||||
" <td>1485.248506</td>\n",
|
||||
" <td>1047469.06</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>184</th>\n",
|
||||
" <td>2025-10-10</td>\n",
|
||||
" <td>197474.435482</td>\n",
|
||||
" <td>198516.516936</td>\n",
|
||||
" <td>199558.598389</td>\n",
|
||||
" <td>197300.755240</td>\n",
|
||||
" <th>2025-10-10</th>\n",
|
||||
" <td>1498.427286</td>\n",
|
||||
" <td>1506.334554</td>\n",
|
||||
" <td>1514.241822</td>\n",
|
||||
" <td>1497.109408</td>\n",
|
||||
" <td>1087947.75</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>185</th>\n",
|
||||
" <td>2025-10-13</td>\n",
|
||||
" <td>196606.034270</td>\n",
|
||||
" <td>197995.476209</td>\n",
|
||||
" <td>199037.557663</td>\n",
|
||||
" <td>195911.313301</td>\n",
|
||||
" <th>2025-10-13</th>\n",
|
||||
" <td>1491.837896</td>\n",
|
||||
" <td>1502.380920</td>\n",
|
||||
" <td>1510.288188</td>\n",
|
||||
" <td>1486.566384</td>\n",
|
||||
" <td>1168801.73</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>186</th>\n",
|
||||
" <td>2025-10-14</td>\n",
|
||||
" <td>197821.795966</td>\n",
|
||||
" <td>200948.040328</td>\n",
|
||||
" <td>201469.081055</td>\n",
|
||||
" <td>197300.755240</td>\n",
|
||||
" <th>2025-10-14</th>\n",
|
||||
" <td>1501.063042</td>\n",
|
||||
" <td>1524.784846</td>\n",
|
||||
" <td>1528.738480</td>\n",
|
||||
" <td>1497.109408</td>\n",
|
||||
" <td>1843428.36</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>187</th>\n",
|
||||
" <td>2025-10-15</td>\n",
|
||||
" <td>205385.713015</td>\n",
|
||||
" <td>206472.409910</td>\n",
|
||||
" <td>206834.642208</td>\n",
|
||||
" <td>203936.783823</td>\n",
|
||||
" <th>2025-10-15</th>\n",
|
||||
" <td>1526.130396</td>\n",
|
||||
" <td>1534.205160</td>\n",
|
||||
" <td>1536.896748</td>\n",
|
||||
" <td>1515.364044</td>\n",
|
||||
" <td>1271061.03</td>\n",
|
||||
" <td>134.5794</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
@@ -394,12 +401,303 @@
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"execution_count": 88,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 5
|
||||
"execution_count": 88
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-20T02:28:38.147008Z",
|
||||
"start_time": "2026-01-20T02:28:38.094513Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"dailies_df['sma30'] = dailies_df['Close'].rolling(10).mean()\n",
|
||||
"dailies_df['sma60'] = dailies_df['Close'].rolling(30).mean()\n",
|
||||
"dailies_df.tail()"
|
||||
],
|
||||
"id": "c558d68773d228c1",
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" Open Close High Low Volume \\\n",
|
||||
"trade_date \n",
|
||||
"2025-10-09 1493.155774 1502.380920 1503.698798 1485.248506 1047469.06 \n",
|
||||
"2025-10-10 1498.427286 1506.334554 1514.241822 1497.109408 1087947.75 \n",
|
||||
"2025-10-13 1491.837896 1502.380920 1510.288188 1486.566384 1168801.73 \n",
|
||||
"2025-10-14 1501.063042 1524.784846 1528.738480 1497.109408 1843428.36 \n",
|
||||
"2025-10-15 1526.130396 1534.205160 1536.896748 1515.364044 1271061.03 \n",
|
||||
"\n",
|
||||
" factor sma30 sma60 \n",
|
||||
"trade_date \n",
|
||||
"2025-10-09 131.7878 1504.094161 1546.925196 \n",
|
||||
"2025-10-10 131.7878 1504.357737 1543.762289 \n",
|
||||
"2025-10-13 131.7878 1503.698798 1540.862958 \n",
|
||||
"2025-10-14 131.7878 1506.202766 1536.997182 \n",
|
||||
"2025-10-15 134.5794 1507.803737 1533.840781 "
|
||||
],
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>Open</th>\n",
|
||||
" <th>Close</th>\n",
|
||||
" <th>High</th>\n",
|
||||
" <th>Low</th>\n",
|
||||
" <th>Volume</th>\n",
|
||||
" <th>factor</th>\n",
|
||||
" <th>sma30</th>\n",
|
||||
" <th>sma60</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>trade_date</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>2025-10-09</th>\n",
|
||||
" <td>1493.155774</td>\n",
|
||||
" <td>1502.380920</td>\n",
|
||||
" <td>1503.698798</td>\n",
|
||||
" <td>1485.248506</td>\n",
|
||||
" <td>1047469.06</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" <td>1504.094161</td>\n",
|
||||
" <td>1546.925196</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2025-10-10</th>\n",
|
||||
" <td>1498.427286</td>\n",
|
||||
" <td>1506.334554</td>\n",
|
||||
" <td>1514.241822</td>\n",
|
||||
" <td>1497.109408</td>\n",
|
||||
" <td>1087947.75</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" <td>1504.357737</td>\n",
|
||||
" <td>1543.762289</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2025-10-13</th>\n",
|
||||
" <td>1491.837896</td>\n",
|
||||
" <td>1502.380920</td>\n",
|
||||
" <td>1510.288188</td>\n",
|
||||
" <td>1486.566384</td>\n",
|
||||
" <td>1168801.73</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" <td>1503.698798</td>\n",
|
||||
" <td>1540.862958</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2025-10-14</th>\n",
|
||||
" <td>1501.063042</td>\n",
|
||||
" <td>1524.784846</td>\n",
|
||||
" <td>1528.738480</td>\n",
|
||||
" <td>1497.109408</td>\n",
|
||||
" <td>1843428.36</td>\n",
|
||||
" <td>131.7878</td>\n",
|
||||
" <td>1506.202766</td>\n",
|
||||
" <td>1536.997182</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2025-10-15</th>\n",
|
||||
" <td>1526.130396</td>\n",
|
||||
" <td>1534.205160</td>\n",
|
||||
" <td>1536.896748</td>\n",
|
||||
" <td>1515.364044</td>\n",
|
||||
" <td>1271061.03</td>\n",
|
||||
" <td>134.5794</td>\n",
|
||||
" <td>1507.803737</td>\n",
|
||||
" <td>1533.840781</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"execution_count": 97,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 97
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-20T02:28:09.232747Z",
|
||||
"start_time": "2026-01-20T02:28:09.215190Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from backtesting import Strategy\n",
|
||||
"from backtesting.lib import crossover\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class SmaCross(Strategy):\n",
|
||||
" def init(self):\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def next(self):\n",
|
||||
" if crossover(self.data.sma30, self.data.sma60):\n",
|
||||
" self.position.close()\n",
|
||||
" self.buy()\n",
|
||||
" elif crossover(self.data.sma60, self.data.sma30):\n",
|
||||
" self.position.close()\n",
|
||||
" self.sell()"
|
||||
],
|
||||
"id": "b56aaaf4cad7bc7d",
|
||||
"outputs": [],
|
||||
"execution_count": 94
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-20T02:28:12.350117Z",
|
||||
"start_time": "2026-01-20T02:28:12.330024Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"def stats_print(stats):\n",
|
||||
" indicator_name_mapping = {\n",
|
||||
" 'Start': '回测开始时间',\n",
|
||||
" 'End': '回测结束时间',\n",
|
||||
" 'Duration': '回测持续时长',\n",
|
||||
" 'Exposure Time [%]': '持仓时间占比(%)',\n",
|
||||
" 'Equity Final [$]': '最终权益',\n",
|
||||
" 'Equity Peak [$]': '权益峰值',\n",
|
||||
" 'Return [%]': '总收益率(%)',\n",
|
||||
" 'Buy & Hold Return [%]': '买入并持有收益率(%)',\n",
|
||||
" 'Return (Ann.) [%]': '年化收益率(%)',\n",
|
||||
" 'Volatility (Ann.) [%]': '年化波动率(%)',\n",
|
||||
" 'CAGR [%]': '复合年均增长率(%)',\n",
|
||||
" 'Sharpe Ratio': '夏普比率',\n",
|
||||
" 'Sortino Ratio': '索提诺比率',\n",
|
||||
" 'Calmar Ratio': '卡尔玛比率',\n",
|
||||
" 'Alpha [%]': '阿尔法系数(%)',\n",
|
||||
" 'Beta': '贝塔系数',\n",
|
||||
" 'Max. Drawdown [%]': '最大回撤(%)',\n",
|
||||
" 'Avg. Drawdown [%]': '平均回撤(%)',\n",
|
||||
" 'Max. Drawdown Duration': '最大回撤持续时长',\n",
|
||||
" 'Avg. Drawdown Duration': '平均回撤持续时长',\n",
|
||||
" '# Trades': '交易总次数',\n",
|
||||
" 'Win Rate [%]': '胜率(%)',\n",
|
||||
" 'Best Trade [%]': '最佳单笔交易收益率(%)',\n",
|
||||
" 'Worst Trade [%]': '最差单笔交易收益率(%)',\n",
|
||||
" 'Avg. Trade [%]': '平均单笔交易收益率(%)',\n",
|
||||
" 'Max. Trade Duration': '单笔交易最长持有时长',\n",
|
||||
" 'Avg. Trade Duration': '单笔交易平均持有时长',\n",
|
||||
" 'Profit Factor': '盈利因子',\n",
|
||||
" 'Expectancy [%]': '期望收益(%)',\n",
|
||||
" 'SQN': '系统质量数',\n",
|
||||
" 'Kelly Criterion': '凯利准则',\n",
|
||||
" }\n",
|
||||
" for k, v in stats.items():\n",
|
||||
" if k in indicator_name_mapping:\n",
|
||||
" cn_name = indicator_name_mapping.get(k, k)\n",
|
||||
" if isinstance(v, (int, float)):\n",
|
||||
" if \"%\" in cn_name or k in ['Sharpe Ratio', 'Sortino Ratio', 'Calmar Ratio', 'Profit Factor']:\n",
|
||||
" formatted_value = f\"{v:.2f}\"\n",
|
||||
" elif \"$\" in cn_name:\n",
|
||||
" formatted_value = f\"{v:.2f}\"\n",
|
||||
" elif \"次数\" in cn_name:\n",
|
||||
" formatted_value = f\"{v:.0f}\"\n",
|
||||
" else:\n",
|
||||
" formatted_value = f\"{v:.4f}\"\n",
|
||||
" else:\n",
|
||||
" formatted_value = str(v)\n",
|
||||
" print(f'{cn_name}: {formatted_value}')"
|
||||
],
|
||||
"id": "a23e811212958477",
|
||||
"outputs": [],
|
||||
"execution_count": 95
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-20T02:28:43.128279Z",
|
||||
"start_time": "2026-01-20T02:28:43.044156Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from backtesting import Backtest\n",
|
||||
"\n",
|
||||
"bt = Backtest(dailies_df, SmaCross, cash=100000, commission=.002, finalize_trades=True)\n",
|
||||
"stats = bt.run()\n",
|
||||
"stats_print(stats)"
|
||||
],
|
||||
"id": "afc750727129ff2e",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"回测开始时间: 2025-01-02 00:00:00\n",
|
||||
"回测结束时间: 2025-10-15 00:00:00\n",
|
||||
"回测持续时长: 286 days 00:00:00\n",
|
||||
"持仓时间占比(%): 71.81\n",
|
||||
"最终权益: 114727.4805\n",
|
||||
"权益峰值: 117838.4813\n",
|
||||
"总收益率(%): 14.73\n",
|
||||
"买入并持有收益率(%): 5.04\n",
|
||||
"年化收益率(%): 20.22\n",
|
||||
"年化波动率(%): 17.17\n",
|
||||
"复合年均增长率(%): 12.87\n",
|
||||
"夏普比率: 1.18\n",
|
||||
"索提诺比率: 2.45\n",
|
||||
"卡尔玛比率: 2.21\n",
|
||||
"阿尔法系数(%): 14.96\n",
|
||||
"贝塔系数: -0.0456\n",
|
||||
"最大回撤(%): -9.13\n",
|
||||
"平均回撤(%): -3.40\n",
|
||||
"最大回撤持续时长: 97 days 00:00:00\n",
|
||||
"平均回撤持续时长: 33 days 00:00:00\n",
|
||||
"交易总次数: 3\n",
|
||||
"胜率(%): 66.67\n",
|
||||
"最佳单笔交易收益率(%): 10.02\n",
|
||||
"最差单笔交易收益率(%): -0.49\n",
|
||||
"平均单笔交易收益率(%): 4.76\n",
|
||||
"单笔交易最长持有时长: 78 days 00:00:00\n",
|
||||
"单笔交易平均持有时长: 68 days 00:00:00\n",
|
||||
"盈利因子: 30.80\n",
|
||||
"期望收益(%): 4.84\n",
|
||||
"系统质量数: 1.6469\n",
|
||||
"凯利准则: 0.6455\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 98
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
126
note.md
Normal file
126
note.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 基础时间与权益指标
|
||||
|
||||
## Exposure Time [%] - 持仓时间占比(%)
|
||||
|
||||
衡量策略在统计周期内实际持有头寸的时间占总时间的百分比。反映策略的“活跃度”(如占比100%=全程持仓,占比低=多数时间空仓),辅助判断交易频率和资金使用效率。
|
||||
|
||||
## Equity Final [$] - 最终权益
|
||||
|
||||
策略运行结束时的账户总资金(本金+盈亏),是最基础的收益结果指标,直接体现最终资金规模。
|
||||
|
||||
## Equity Peak [$] - 权益峰值
|
||||
|
||||
统计周期内账户权益的最大值。对比最终权益可判断策略是否从峰值回落,结合回撤指标能评估收益稳定性。
|
||||
|
||||
# 收益率类指标(核心收益衡量)
|
||||
|
||||
## Return [%] - 总收益率(%)
|
||||
|
||||
周期内总收益占初始本金的百分比(`(最终权益-初始本金)/初始本金×100%`),直观反映整体盈利/亏损程度,但未考虑时间因素。
|
||||
|
||||
## Buy & Hold Return [%] - 买入并持有收益率(%)
|
||||
|
||||
作为“基准收益率”,模拟“买入标的后长期持有不操作”的收益。用于对比策略收益,判断策略是否跑赢简单持有,是评估策略有效性的核心参照。
|
||||
|
||||
## Return (Ann.) [%] - 年化收益率(%)
|
||||
|
||||
将周期总收益折算为按年计算的收益(`(1+总收益率)^(365/持仓天数) - 1`),消除时间周期差异,是跨周期对比不同策略收益的关键指标。
|
||||
|
||||
## CAGR [%] - 复合年均增长率(%)
|
||||
|
||||
即“年均复合收益率”(`(最终权益/初始本金)^(1/年数) - 1`),衡量资金长期复利增长速度,更贴合多年期策略的收益评估,避免短期高收益误导。
|
||||
|
||||
# 风险类指标(衡量亏损与波动风险)
|
||||
|
||||
## Volatility (Ann.) [%] - 年化波动率(%)
|
||||
|
||||
收益波动程度的年化标准差,反映收益稳定性。波动率越高,收益起伏越大,策略“震荡风险”越高;波动率低则收益更平稳。
|
||||
|
||||
## Max. Drawdown [%] - 最大回撤(%)
|
||||
|
||||
权益从峰值回落至谷值的最大幅度(`(峰值-谷值)/峰值×100%`),核心风险指标。比如最大回撤20%,说明策略曾从最高点亏掉20%,直接体现抗风险能力。
|
||||
|
||||
## Avg. Drawdown [%] - 平均回撤(%)
|
||||
|
||||
所有回撤的平均幅度。若最大回撤远高于平均回撤,说明策略曾出现极端亏损;两者接近则回撤风险更均匀。
|
||||
|
||||
## Max. Drawdown Duration - 最大回撤持续时长
|
||||
|
||||
最大回撤从峰值回落至恢复峰值的时间(天/月),反映策略从最大亏损中回血的速度,时长越长则恢复能力越弱。
|
||||
|
||||
## Avg. Drawdown Duration - 平均回撤持续时长
|
||||
|
||||
所有回撤周期的平均时间,辅助判断策略亏损后的恢复效率。
|
||||
|
||||
# 风险收益比指标(性价比核心)
|
||||
|
||||
## Sharpe Ratio - 夏普比率
|
||||
|
||||
衡量“每承担1单位风险的超额收益”(`(年化收益率-无风险利率)/年化波动率`
|
||||
),无风险利率通常取国债利率(3%左右)。比率越高性价比越高(>1较好,>2优秀)。
|
||||
|
||||
## Sortino Ratio - 索提诺比率
|
||||
|
||||
改进版夏普比率,仅用“下行波动率”(亏损方向波动)计算风险,更贴合投资者对“亏损风险”的关注,适合评估稳健型策略。
|
||||
|
||||
## Calmar Ratio - 卡尔玛比率
|
||||
|
||||
`年化收益率/最大回撤(绝对值)`,直接反映“收益能否覆盖最大亏损”,比率越高,策略用小回撤换高收益的能力越强。
|
||||
|
||||
# 资产定价系数(市场相关性)
|
||||
|
||||
## Alpha [%] - 阿尔法系数(%)
|
||||
|
||||
衡量策略“超额收益”(超出市场基准的收益),Alpha为正说明策略能跑赢市场,反映主动管理能力;为负则跑输市场。
|
||||
|
||||
## Beta - 贝塔系数
|
||||
|
||||
衡量策略与市场基准的波动同步性。Beta=1=和市场波动一致;Beta>1=策略更激进(波动更大);Beta<1=策略更稳健;Beta<0=与市场反向波动。
|
||||
|
||||
# 交易行为与质量指标
|
||||
|
||||
## Trades - 交易总次数
|
||||
|
||||
统计周期内总交易笔数,反映策略交易频率(高频/低频),结合胜率可判断策略有效性。
|
||||
|
||||
## Win Rate [%] - 胜率(%)
|
||||
|
||||
盈利交易次数/总次数×100%,直观反映“赚钱交易的比例”,但需结合盈亏比(平均盈利/平均亏损)使用(如胜率50%+盈亏比3:1仍盈利)。
|
||||
|
||||
## Best Trade [%] - 最佳单笔交易收益率(%)
|
||||
|
||||
单次盈利幅度最大值,反映策略盈利上限,但需警惕是否由偶然高收益拉高整体表现。
|
||||
|
||||
## Worst Trade [%] - 最差单笔交易收益率(%)
|
||||
|
||||
单次亏损幅度最大值(通常为负),反映单笔交易的最大亏损风险。
|
||||
|
||||
## Avg. Trade [%] - 平均单笔交易收益率(%)
|
||||
|
||||
所有交易收益率的平均值,反映单笔交易的平均盈利能力,为正则单笔交易平均赚钱。
|
||||
|
||||
## Max. Trade Duration - 单笔交易最长持有时长
|
||||
|
||||
单次持仓的最长时间,定义策略风格(日内/短线/中长线)。
|
||||
|
||||
## Avg. Trade Duration - 单笔交易平均持有时长
|
||||
|
||||
所有交易持仓时长的平均值,辅助判断资金周转效率。
|
||||
|
||||
# 综合绩效指标(策略可持续性)
|
||||
|
||||
## Profit Factor - 盈利因子
|
||||
|
||||
`总盈利金额/总亏损金额(绝对值)`,核心指标。>1说明总盈利>总亏损,数值越高盈利能力越强(如盈利因子2=每亏1元赚2元)。
|
||||
|
||||
## Expectancy [%] - 期望收益(%)
|
||||
|
||||
每笔交易的预期收益(`胜率×平均盈利 - (1-胜率)×平均亏损`),为正则策略长期可盈利,数值越高预期收益越好。
|
||||
|
||||
## SQN - 系统质量数
|
||||
|
||||
衡量策略收益的“统计显著性”(`√交易次数 × 期望收益 / 交易收益标准差`)。SQN>1.6合格,>2.5优秀,>3.0卓越,判断收益是否为偶然结果。
|
||||
|
||||
## Kelly Criterion - 凯利准则
|
||||
|
||||
计算“最优仓位比例”(`(胜率×(盈亏比+1)-1)/盈亏比`),确定每笔交易的最佳资金投入比例,最大化长期复利收益,同时控制破产风险(实际应用中通常减半使用)。
|
||||
@@ -5,8 +5,10 @@ description = "Stock analysis"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
"backtesting~=0.6.5",
|
||||
"duckdb>=1.4.3",
|
||||
"jupyter~=1.1.1",
|
||||
"matplotlib~=3.10.8",
|
||||
"mplfinance>=0.12.10b0",
|
||||
"pandas~=2.3.3",
|
||||
"pandas-stubs~=2.3.3",
|
||||
"peewee~=3.19.0",
|
||||
|
||||
72
sql2dataframe.ipynb
Normal file
72
sql2dataframe.ipynb
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"host = '81.71.3.24'\n",
|
||||
"port = 6785\n",
|
||||
"database = 'leopard_dev'\n",
|
||||
"username = 'leopard'\n",
|
||||
"password = '9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X'"
|
||||
],
|
||||
"id": "1e8d815ee9b8c936"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "initial_id",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import psycopg2\n",
|
||||
"\n",
|
||||
"dailies_df = pd.DataFrame()\n",
|
||||
"\n",
|
||||
"with psycopg2.connect(host=host, port=port, database=database, user=username, password=password) as connection:\n",
|
||||
" with connection.cursor() as cursor:\n",
|
||||
" # language=PostgreSQL\n",
|
||||
" cursor.execute(\n",
|
||||
" \"\"\"select trade_date, open, close, high, low, factor\n",
|
||||
"from leopard_daily daily\n",
|
||||
" left join leopard_stock stock on stock.id = daily.stock_id\n",
|
||||
"where stock.code = '000001.SZ'\n",
|
||||
" and daily.trade_date between '2025-01-01 00:00:00' and '2025-12-31 23:59:59'\n",
|
||||
"order by daily.trade_date\"\"\"\n",
|
||||
" )\n",
|
||||
" rows = cursor.fetchall()\n",
|
||||
"\n",
|
||||
" dailies_df = pd.DataFrame.from_records(rows, columns=['trade_date', 'open', 'close', 'high', 'low', 'factor'])\n",
|
||||
"\n",
|
||||
"dailies_df"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
32
uv.lock
generated
32
uv.lock
generated
@@ -338,6 +338,21 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "duckdb"
|
||||
version = "1.4.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7f/da/17c3eb5458af69d54dedc8d18e4a32ceaa8ce4d4c699d45d6d8287e790c3/duckdb-1.4.3.tar.gz", hash = "sha256:fea43e03604c713e25a25211ada87d30cd2a044d8f27afab5deba26ac49e5268", size = 18478418, upload-time = "2025-12-09T10:59:22.945Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/f4/a38651e478fa41eeb8e43a0a9c0d4cd8633adea856e3ac5ac95124b0fdbf/duckdb-1.4.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:316711a9e852bcfe1ed6241a5f654983f67e909e290495f3562cccdf43be8180", size = 29042272, upload-time = "2025-12-09T10:58:51.826Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/de/2cf171a66098ce5aeeb7371511bd2b3d7b73a2090603b0b9df39f8aaf814/duckdb-1.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9e625b2b4d52bafa1fd0ebdb0990c3961dac8bb00e30d327185de95b68202131", size = 15419343, upload-time = "2025-12-09T10:58:54.439Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/28/6b0a7830828d4e9a37420d87e80fe6171d2869a9d3d960bf5d7c3b8c7ee4/duckdb-1.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:130c6760f6c573f9c9fe9aba56adba0fab48811a4871b7b8fd667318b4a3e8da", size = 13748905, upload-time = "2025-12-09T10:58:56.656Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/4d/778628e194d63967870873b9581c8a6b4626974aa4fbe09f32708a2d3d3a/duckdb-1.4.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20c88effaa557a11267706b01419c542fe42f893dee66e5a6daa5974ea2d4a46", size = 18487261, upload-time = "2025-12-09T10:58:58.866Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/5f/87e43af2e4a0135f9675449563e7c2f9b6f1fe6a2d1691c96b091f3904dd/duckdb-1.4.3-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1b35491db98ccd11d151165497c084a9d29d3dc42fc80abea2715a6c861ca43d", size = 20497138, upload-time = "2025-12-09T10:59:01.241Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/41/abec537cc7c519121a2a83b9a6f180af8915fabb433777dc147744513e74/duckdb-1.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:23b12854032c1a58d0452e2b212afa908d4ce64171862f3792ba9a596ba7c765", size = 12836056, upload-time = "2025-12-09T10:59:03.388Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/5a/8af5b96ce5622b6168854f479ce846cf7fb589813dcc7d8724233c37ded3/duckdb-1.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:90f241f25cffe7241bf9f376754a5845c74775e00e1c5731119dc88cd71e0cb2", size = 13527759, upload-time = "2025-12-09T10:59:05.496Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "executing"
|
||||
version = "2.2.1"
|
||||
@@ -850,8 +865,10 @@ version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "backtesting" },
|
||||
{ name = "duckdb" },
|
||||
{ name = "jupyter" },
|
||||
{ name = "matplotlib" },
|
||||
{ name = "mplfinance" },
|
||||
{ name = "pandas" },
|
||||
{ name = "pandas-stubs" },
|
||||
{ name = "peewee" },
|
||||
@@ -861,8 +878,10 @@ dependencies = [
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "backtesting", specifier = "~=0.6.5" },
|
||||
{ name = "duckdb", specifier = ">=1.4.3" },
|
||||
{ name = "jupyter", specifier = "~=1.1.1" },
|
||||
{ name = "matplotlib", specifier = "~=3.10.8" },
|
||||
{ name = "mplfinance", specifier = ">=0.12.10b0" },
|
||||
{ name = "pandas", specifier = "~=2.3.3" },
|
||||
{ name = "pandas-stubs", specifier = "~=2.3.3" },
|
||||
{ name = "peewee", specifier = "~=3.19.0" },
|
||||
@@ -953,6 +972,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mplfinance"
|
||||
version = "0.12.10b0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "matplotlib" },
|
||||
{ name = "pandas" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6c/a9/34e7998d02fb58fae04f750444ce4e95e75f3a08dad17fb2d32098a97834/mplfinance-0.12.10b0.tar.gz", hash = "sha256:7da150b5851aa5119ad6e06b55e48338b619bb6773f1b85df5de67a5ffd917bf", size = 70117, upload-time = "2023-08-02T15:13:53.829Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/d9/31c436ea7673c21a5bf3fc747bc7f63377582dfe845c3004d3e46f9deee0/mplfinance-0.12.10b0-py3-none-any.whl", hash = "sha256:76d3b095f05ff35de730751649de063bea4064d0c49b21b6182c82997a7f52bb", size = 75016, upload-time = "2023-08-02T15:13:52.022Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "narwhals"
|
||||
version = "2.15.0"
|
||||
|
||||
Reference in New Issue
Block a user