Compare commits
5 Commits
5554abc245
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 48c6154fab | |||
| 3174f306bb | |||
| b90d030899 | |||
| 9f06ebf87d | |||
| d4db4f3021 |
7
.idea/dataSources.xml
generated
7
.idea/dataSources.xml
generated
@@ -8,5 +8,12 @@
|
||||
<jdbc-url>jdbc:postgresql://81.71.3.24:6785/leopard_dev</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="leopard.sqlite" uuid="c9e16f8e-81be-45cf-847c-47a6750eeee2">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$USER_HOME$/Documents/leopard_data/leopard.sqlite</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/data_source_mapping.xml
generated
Normal file
7
.idea/data_source_mapping.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourcePerFileMappings">
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/bd7b5f2a-eb99-4aad-81ec-1fec76b3d7fc/console.sql" value="bd7b5f2a-eb99-4aad-81ec-1fec76b3d7fc" />
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/c9e16f8e-81be-45cf-847c-47a6750eeee2/console.sql" value="c9e16f8e-81be-45cf-847c-47a6750eeee2" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/db-forest-config.xml
generated
Normal file
6
.idea/db-forest-config.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="db-tree-configuration">
|
||||
<option name="data" value="" />
|
||||
</component>
|
||||
</project>
|
||||
1
.idea/sqldialects.xml
generated
1
.idea/sqldialects.xml
generated
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/sql/initial.sql" dialect="SQLite" />
|
||||
<file url="PROJECT" dialect="PostgreSQL" />
|
||||
</component>
|
||||
</project>
|
||||
136
data.py
Normal file
136
data.py
Normal file
@@ -0,0 +1,136 @@
|
||||
from datetime import date, datetime, timedelta
|
||||
from time import sleep
|
||||
|
||||
from sqlalchemy import Column, Double, Integer, String, create_engine
|
||||
from sqlalchemy.orm import DeclarativeBase, Session
|
||||
from tushare import pro_api
|
||||
|
||||
TUSHARE_API_KEY = '64ebff4fa679167600b905ee45dd88e76f3963c0ff39157f3f085f0e'
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class Stock(Base):
|
||||
__tablename__ = 'stock'
|
||||
|
||||
code = Column(String, primary_key=True, comment="代码")
|
||||
name = Column(String, comment="名称")
|
||||
fullname = Column(String, comment="全名")
|
||||
market = Column(String, comment="市场")
|
||||
exchange = Column(String, comment="交易所")
|
||||
industry = Column(String, comment="行业")
|
||||
list_date = Column(String, comment="上市日期")
|
||||
|
||||
|
||||
class Daily(Base):
|
||||
__tablename__ = 'daily'
|
||||
|
||||
code = Column(String, primary_key=True)
|
||||
trade_date = Column(String, primary_key=True)
|
||||
open = Column(Double)
|
||||
close = Column(Double)
|
||||
high = Column(Double)
|
||||
low = Column(Double)
|
||||
previous_close = Column(Double)
|
||||
turnover = Column(Double)
|
||||
volume = Column(Integer)
|
||||
price_change_amount = Column(Double)
|
||||
factor = Column(Double)
|
||||
|
||||
|
||||
def main():
|
||||
print("开始更新数据")
|
||||
|
||||
engine = create_engine(f"sqlite:////Users/lanyuanxiaoyao/Documents/leopard_data/leopard.sqlite")
|
||||
try:
|
||||
Stock.metadata.create_all(engine, checkfirst=True)
|
||||
Daily.metadata.create_all(engine, checkfirst=True)
|
||||
pro = pro_api(TUSHARE_API_KEY)
|
||||
# with engine.connect() as connection:
|
||||
# stocks = pro.stock_basic(list_status="L", market="主板", fields="ts_code,name,fullname,market,exchange,industry,list_date")
|
||||
# for row in stocks.itertuples():
|
||||
# stmt = insert(Stock).values(
|
||||
# code=row.ts_code,
|
||||
# name=row.name,
|
||||
# fullname=row.fullname,
|
||||
# market=row.market,
|
||||
# exchange=row.exchange,
|
||||
# industry=row.industry,
|
||||
# list_date=row.list_date,
|
||||
# )
|
||||
# stmt = stmt.on_conflict_do_update(
|
||||
# index_elements=["code"],
|
||||
# set_={
|
||||
# "name": stmt.excluded.name,
|
||||
# "fullname": stmt.excluded.fullname,
|
||||
# "market": stmt.excluded.market,
|
||||
# "exchange": stmt.excluded.exchange,
|
||||
# "industry": stmt.excluded.industry,
|
||||
# "list_date": stmt.excluded.list_date,
|
||||
# },
|
||||
# )
|
||||
# print(stmt)
|
||||
# connection.execute(stmt)
|
||||
# connection.commit()
|
||||
#
|
||||
# print("清理行情数据")
|
||||
# connection.execute(text("delete from daily where code not in (select distinct code from stock)"))
|
||||
# connection.commit()
|
||||
#
|
||||
# print("清理财务数据")
|
||||
# connection.execute(text("delete from finance_indicator where code not in (select distinct code from stock)"))
|
||||
# connection.commit()
|
||||
|
||||
with Session(engine) as session:
|
||||
stock_codes = [row[0] for row in session.query(Stock.code).all()]
|
||||
|
||||
latest_date = session.query(Daily.trade_date).order_by(Daily.trade_date.desc()).first()
|
||||
if latest_date is None:
|
||||
latest_date = '1990-12-19'
|
||||
else:
|
||||
latest_date = latest_date.trade_date
|
||||
latest_date = datetime.strptime(latest_date, '%Y-%m-%d').date()
|
||||
current_date = date.today() - timedelta(days=1)
|
||||
delta = (current_date - latest_date).days
|
||||
print(f"最新数据日期:{latest_date},当前日期:{current_date},待更新天数:{delta}")
|
||||
if delta > 0:
|
||||
update_dates = []
|
||||
for i in range(delta):
|
||||
latest_date = latest_date + timedelta(days=1)
|
||||
update_dates.append(latest_date.strftime('%Y%m%d'))
|
||||
for target_date in update_dates:
|
||||
print(f"正在采集:{target_date}")
|
||||
dailies = pro.daily(trade_date=target_date)
|
||||
dailies.set_index("ts_code", inplace=True)
|
||||
factors = pro.adj_factor(trade_date=target_date)
|
||||
factors.set_index("ts_code", inplace=True)
|
||||
results = dailies.join(factors, lsuffix="_daily", rsuffix="_factor", how="left")
|
||||
rows = []
|
||||
for row in results.itertuples():
|
||||
if row.Index in stock_codes:
|
||||
rows.append(
|
||||
Daily(
|
||||
code=row.Index,
|
||||
trade_date=datetime.strptime(target_date, '%Y%m%d').strftime("%Y-%m-%d"),
|
||||
open=row.open,
|
||||
close=row.close,
|
||||
high=row.high,
|
||||
low=row.low,
|
||||
previous_close=row.pre_close,
|
||||
turnover=row.amount,
|
||||
volume=row.vol,
|
||||
price_change_amount=row.pct_chg,
|
||||
factor=row.adj_factor,
|
||||
)
|
||||
)
|
||||
session.add_all(rows)
|
||||
session.commit()
|
||||
sleep(1)
|
||||
finally:
|
||||
engine.dispose()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1088
notebook/backtest.ipynb
Normal file
1088
notebook/backtest.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -1,184 +0,0 @@
|
||||
import marimo
|
||||
|
||||
__generated_with = "0.19.6"
|
||||
app = marimo.App(width="full", auto_download=["ipynb"], sql_output="pandas")
|
||||
|
||||
|
||||
@app.cell
|
||||
def _():
|
||||
import marimo as mo
|
||||
return (mo,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _():
|
||||
import urllib
|
||||
import sqlalchemy
|
||||
|
||||
host = "81.71.3.24"
|
||||
port = 6785
|
||||
username = "leopard"
|
||||
password = urllib.parse.quote_plus("9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X")
|
||||
database = "leopard_dev"
|
||||
engine = sqlalchemy.create_engine(f"postgresql://{username}:{password}@{host}:{port}/{database}")
|
||||
return (engine,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(engine, mo):
|
||||
dailies_df = mo.sql(
|
||||
f"""
|
||||
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
|
||||
from leopard_daily daily
|
||||
left join leopard_stock stock on stock.id = daily.stock_id
|
||||
where stock.code = '000001.SZ'
|
||||
and daily.trade_date between '2024-01-01 00:00:00' and '2025-12-31 23:59:59'
|
||||
order by daily.trade_date
|
||||
""",
|
||||
engine=engine
|
||||
)
|
||||
return (dailies_df,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(dailies_df):
|
||||
import pandas as pd
|
||||
|
||||
dailies_df.rename(
|
||||
columns={'open': 'Open', 'close': 'Close', 'high': 'High', 'low': 'Low', 'volume': 'Volume'}, inplace=True
|
||||
)
|
||||
dailies_df['trade_date'] = pd.to_datetime(dailies_df['trade_date'], format='%Y-%m-%d')
|
||||
dailies_df.set_index('trade_date', inplace=True)
|
||||
dailies_df
|
||||
return
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(dailies_df):
|
||||
import talib
|
||||
|
||||
dailies_df['sma10'] = talib.SMA(dailies_df['Close'], timeperiod=10)
|
||||
dailies_df['sma30'] = talib.SMA(dailies_df['Close'], timeperiod=30)
|
||||
dailies_df['sma60'] = talib.SMA(dailies_df['Close'], timeperiod=60)
|
||||
dailies_df['sma120'] = talib.SMA(dailies_df['Close'], timeperiod=120)
|
||||
dailies_df
|
||||
return
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(dailies_df):
|
||||
# 指标计算完成后截取后面指标的完整的部份使用
|
||||
target_dailies_df = dailies_df.loc['2025-01-01':'2025-12-31']
|
||||
target_dailies_df
|
||||
return (target_dailies_df,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _():
|
||||
from backtesting import Strategy
|
||||
from backtesting.lib import crossover
|
||||
|
||||
class SmaCross(Strategy):
|
||||
def init(self):
|
||||
self.sma10 = self.I(lambda x: x, self.data.sma10)
|
||||
self.sma30 = self.I(lambda x: x, self.data.sma30)
|
||||
self.sma60 = self.I(lambda x: x, self.data.sma60)
|
||||
# self.sma120 = self.I(lambda x: x, self.data.sma120)
|
||||
|
||||
def next(self):
|
||||
if self.sma60 > 0 and crossover(self.data.sma10, self.data.sma30):
|
||||
self.buy()
|
||||
elif self.position.size > 0 and crossover(self.data.sma30, self.data.sma10):
|
||||
self.position.close()
|
||||
return (SmaCross,)
|
||||
|
||||
|
||||
@app.function
|
||||
def stats_print(stats):
|
||||
indicator_name_mapping = {
|
||||
# 'Start': '回测开始时间',
|
||||
# 'End': '回测结束时间',
|
||||
# 'Duration': '回测持续时长',
|
||||
# 'Exposure Time [%]': '持仓时间占比(%)',
|
||||
'Equity Final [$]': '最终收益',
|
||||
'Equity Peak [$]': '峰值收益',
|
||||
'Return [%]': '总收益率(%)',
|
||||
'Buy & Hold Return [%]': '买入并持有收益率(%)',
|
||||
'Return (Ann.) [%]': '年化收益率(%)',
|
||||
'Volatility (Ann.) [%]': '年化波动率(%)',
|
||||
# 'CAGR [%]': '复合年均增长率(%)',
|
||||
# 'Sharpe Ratio': '夏普比率',
|
||||
'Sortino Ratio': '索提诺比率',
|
||||
'Calmar Ratio': '卡尔玛比率',
|
||||
# 'Alpha [%]': '阿尔法系数(%)',
|
||||
# 'Beta': '贝塔系数',
|
||||
'Max. Drawdown [%]': '最大回撤(%)',
|
||||
'Avg. Drawdown [%]': '平均回撤(%)',
|
||||
'Max. Drawdown Duration': '最大回撤持续时长',
|
||||
'Avg. Drawdown Duration': '平均回撤持续时长',
|
||||
'# Trades': '总交易次数',
|
||||
'Win Rate [%]': '胜率(%)',
|
||||
# 'Best Trade [%]': '最佳单笔交易收益率(%)',
|
||||
# 'Worst Trade [%]': '最差单笔交易收益率(%)',
|
||||
# 'Avg. Trade [%]': '平均单笔交易收益率(%)',
|
||||
# 'Max. Trade Duration': '单笔交易最长持有时长',
|
||||
# 'Avg. Trade Duration': '单笔交易平均持有时长',
|
||||
# 'Profit Factor': '盈利因子',
|
||||
# 'Expectancy [%]': '期望收益(%)',
|
||||
'SQN': '系统质量数',
|
||||
# 'Kelly Criterion': '凯利准则',
|
||||
}
|
||||
for k, v in stats.items():
|
||||
if k in indicator_name_mapping:
|
||||
cn_name = indicator_name_mapping.get(k, k)
|
||||
if isinstance(v, (int, float)):
|
||||
if "%" in cn_name or k in ['Sharpe Ratio', 'Sortino Ratio', 'Calmar Ratio', 'Profit Factor']:
|
||||
formatted_value = f"{v:.2f}"
|
||||
elif "$" in cn_name:
|
||||
formatted_value = f"{v:.2f}"
|
||||
elif "次数" in cn_name:
|
||||
formatted_value = f"{v:.0f}"
|
||||
else:
|
||||
formatted_value = f"{v:.4f}"
|
||||
else:
|
||||
formatted_value = str(v)
|
||||
print(f'{cn_name}: {formatted_value}')
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(SmaCross, target_dailies_df):
|
||||
from backtesting import Backtest
|
||||
|
||||
import backtesting._plotting as plotting
|
||||
from bokeh.colors.named import tomato, lime
|
||||
|
||||
plotting.BULL_COLOR = tomato
|
||||
plotting.BEAR_COLOR = lime
|
||||
|
||||
bt = Backtest(target_dailies_df, SmaCross, cash=100000, commission=.002, finalize_trades=True)
|
||||
stats = bt.run()
|
||||
stats_print(stats)
|
||||
return bt, stats
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(stats):
|
||||
stats._trades
|
||||
# stats._equity_curve
|
||||
return
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(bt):
|
||||
bt.plot()
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
1300
notebook/datasource/data.ipynb
Normal file
1300
notebook/datasource/data.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
455
notebook/datasource/data_old.ipynb
Normal file
455
notebook/datasource/data_old.ipynb
Normal file
@@ -0,0 +1,455 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-30T05:41:51.291397Z",
|
||||
"start_time": "2026-01-30T04:34:22.917761Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import urllib.parse\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"import sqlalchemy\n",
|
||||
"from sqlalchemy import text\n",
|
||||
"from sqlalchemy.orm import DeclarativeBase, Session\n",
|
||||
"\n",
|
||||
"postgresql_engin = sqlalchemy.create_engine(\n",
|
||||
" f\"postgresql://leopard:{urllib.parse.quote_plus(\"9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X\")}@81.71.3.24:6785/leopard\"\n",
|
||||
")\n",
|
||||
"sqlite_engine = sqlalchemy.create_engine(f\"sqlite:////Users/lanyuanxiaoyao/Documents/leopard_data/leopard.sqlite\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Base(DeclarativeBase):\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Daily(Base):\n",
|
||||
" __tablename__ = 'daily'\n",
|
||||
"\n",
|
||||
" code = sqlalchemy.Column(sqlalchemy.String, primary_key=True)\n",
|
||||
" trade_date = sqlalchemy.Column(sqlalchemy.Date, primary_key=True)\n",
|
||||
" open = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" close = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" high = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" low = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" previous_close = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" turnover = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" volume = sqlalchemy.Column(sqlalchemy.Integer)\n",
|
||||
" price_change_amount = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
" factor = sqlalchemy.Column(sqlalchemy.Double)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" with Session(postgresql_engin) as pg_session:\n",
|
||||
" results = pg_session.execute(text(\"select distinct trade_date from leopard_daily\")).fetchall()\n",
|
||||
" results = list(map(lambda x: x[0].strftime(\"%Y-%m-%d\"), results))\n",
|
||||
" dates = [results[i: i + 30] for i in range(0, len(results), 30)]\n",
|
||||
"\n",
|
||||
" for index, date in enumerate(dates):\n",
|
||||
" print(date)\n",
|
||||
" daily_df = pd.read_sql(\n",
|
||||
" f\"\"\"\n",
|
||||
" select code,\n",
|
||||
" trade_date,\n",
|
||||
" open,\n",
|
||||
" close,\n",
|
||||
" high,\n",
|
||||
" low,\n",
|
||||
" previous_close,\n",
|
||||
" turnover,\n",
|
||||
" volume,\n",
|
||||
" price_change_amount,\n",
|
||||
" factor\n",
|
||||
" from leopard_daily d\n",
|
||||
" left join leopard_stock s on d.stock_id = s.id\n",
|
||||
" where d.trade_date in ('{\"','\".join(date)}')\n",
|
||||
" \"\"\",\n",
|
||||
" postgresql_engin\n",
|
||||
" )\n",
|
||||
" with Session(sqlite_engine) as session:\n",
|
||||
" rows = []\n",
|
||||
" for _, row in daily_df.iterrows():\n",
|
||||
" rows.append(\n",
|
||||
" Daily(\n",
|
||||
" code=row[\"code\"],\n",
|
||||
" trade_date=row[\"trade_date\"],\n",
|
||||
" open=row[\"open\"],\n",
|
||||
" close=row[\"close\"],\n",
|
||||
" high=row[\"high\"],\n",
|
||||
" low=row[\"low\"],\n",
|
||||
" previous_close=row[\"previous_close\"],\n",
|
||||
" turnover=row[\"turnover\"],\n",
|
||||
" volume=row[\"volume\"],\n",
|
||||
" price_change_amount=row[\"price_change_amount\"],\n",
|
||||
" factor=row[\"factor\"]\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" session.add_all(rows)\n",
|
||||
" session.commit()\n",
|
||||
"finally:\n",
|
||||
" postgresql_engin.dispose()\n",
|
||||
" sqlite_engine.dispose()"
|
||||
],
|
||||
"id": "48821306efc640a1",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"['2025-12-25', '2025-12-26', '2025-12-29', '2025-12-30', '2025-12-31', '2026-01-05', '2026-01-06', '2026-01-07', '2026-01-08', '2026-01-09']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 22
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-30T09:24:09.859231Z",
|
||||
"start_time": "2026-01-30T09:24:09.746912Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import tushare as ts\n",
|
||||
"\n",
|
||||
"pro = ts.pro_api(\"64ebff4fa679167600b905ee45dd88e76f3963c0ff39157f3f085f0e\")\n",
|
||||
"# stocks = pro.stock_basic(ts_code=\"600200.SH\", list_status=\"D\", fields=\"ts_code,name,fullname,market,exchange,industry,list_date,delist_date\")\n",
|
||||
"# stocks"
|
||||
],
|
||||
"id": "ed58a1faaf2cdb8e",
|
||||
"outputs": [],
|
||||
"execution_count": 34
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-30T07:14:29.897120Z",
|
||||
"start_time": "2026-01-30T07:14:29.664124Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": "# stocks.to_csv(\"dlist.csv\")",
|
||||
"id": "3c8c0a38d6b2992e",
|
||||
"outputs": [],
|
||||
"execution_count": 24
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-30T09:46:34.808300Z",
|
||||
"start_time": "2026-01-30T09:46:34.129412Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"daily_df = pro.daily(trade_date=\"20251231\")\n",
|
||||
"daily_df.set_index(\"ts_code\", inplace=True)\n",
|
||||
"factor_df = pro.adj_factor(trade_date=\"20251231\")\n",
|
||||
"factor_df.set_index(\"ts_code\", inplace=True)"
|
||||
],
|
||||
"id": "c052a945869aa329",
|
||||
"outputs": [],
|
||||
"execution_count": 50
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2026-01-30T09:46:36.697015Z",
|
||||
"start_time": "2026-01-30T09:46:36.642975Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"result_df = daily_df.join(factor_df, lsuffix=\"_daily\", rsuffix=\"_factor\", how=\"left\")\n",
|
||||
"result_df\n",
|
||||
"# factor_df"
|
||||
],
|
||||
"id": "d61ee80d2cd9f06b",
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" trade_date_daily open high low close pre_close change \\\n",
|
||||
"ts_code \n",
|
||||
"000001.SZ 20251231 11.48 11.49 11.40 11.41 11.48 -0.07 \n",
|
||||
"000002.SZ 20251231 4.66 4.68 4.62 4.65 4.62 0.03 \n",
|
||||
"000004.SZ 20251231 11.30 11.35 11.07 11.08 11.27 -0.19 \n",
|
||||
"000006.SZ 20251231 9.95 10.03 9.69 9.95 9.86 0.09 \n",
|
||||
"000007.SZ 20251231 11.72 11.75 11.28 11.44 11.62 -0.18 \n",
|
||||
"... ... ... ... ... ... ... ... \n",
|
||||
"920978.BJ 20251231 37.64 38.39 36.88 36.90 37.78 -0.88 \n",
|
||||
"920981.BJ 20251231 32.20 32.29 31.75 31.96 32.07 -0.11 \n",
|
||||
"920982.BJ 20251231 233.00 238.49 232.10 233.70 234.80 -1.10 \n",
|
||||
"920985.BJ 20251231 7.32 7.35 7.17 7.19 7.30 -0.11 \n",
|
||||
"920992.BJ 20251231 17.33 17.60 17.29 17.39 17.38 0.01 \n",
|
||||
"\n",
|
||||
" pct_chg vol amount trade_date_factor adj_factor \n",
|
||||
"ts_code \n",
|
||||
"000001.SZ -0.6098 590620.37 675457.357 20251231 134.5794 \n",
|
||||
"000002.SZ 0.6494 1075561.25 499883.113 20251231 181.7040 \n",
|
||||
"000004.SZ -1.6859 18056.00 20248.567 20251231 4.0640 \n",
|
||||
"000006.SZ 0.9128 270369.08 267758.676 20251231 39.7400 \n",
|
||||
"000007.SZ -1.5491 80556.00 92109.366 20251231 8.2840 \n",
|
||||
"... ... ... ... ... ... \n",
|
||||
"920978.BJ -2.3293 33945.04 126954.937 20251231 1.2885 \n",
|
||||
"920981.BJ -0.3430 8237.16 26301.206 20251231 1.4343 \n",
|
||||
"920982.BJ -0.4685 5210.09 122452.646 20251231 4.2831 \n",
|
||||
"920985.BJ -1.5068 35174.30 25350.257 20251231 1.6280 \n",
|
||||
"920992.BJ 0.0575 6991.87 12193.445 20251231 1.4932 \n",
|
||||
"\n",
|
||||
"[5458 rows x 12 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_daily</th>\n",
|
||||
" <th>open</th>\n",
|
||||
" <th>high</th>\n",
|
||||
" <th>low</th>\n",
|
||||
" <th>close</th>\n",
|
||||
" <th>pre_close</th>\n",
|
||||
" <th>change</th>\n",
|
||||
" <th>pct_chg</th>\n",
|
||||
" <th>vol</th>\n",
|
||||
" <th>amount</th>\n",
|
||||
" <th>trade_date_factor</th>\n",
|
||||
" <th>adj_factor</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>ts_code</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",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>000001.SZ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>11.48</td>\n",
|
||||
" <td>11.49</td>\n",
|
||||
" <td>11.40</td>\n",
|
||||
" <td>11.41</td>\n",
|
||||
" <td>11.48</td>\n",
|
||||
" <td>-0.07</td>\n",
|
||||
" <td>-0.6098</td>\n",
|
||||
" <td>590620.37</td>\n",
|
||||
" <td>675457.357</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>134.5794</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>000002.SZ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>4.66</td>\n",
|
||||
" <td>4.68</td>\n",
|
||||
" <td>4.62</td>\n",
|
||||
" <td>4.65</td>\n",
|
||||
" <td>4.62</td>\n",
|
||||
" <td>0.03</td>\n",
|
||||
" <td>0.6494</td>\n",
|
||||
" <td>1075561.25</td>\n",
|
||||
" <td>499883.113</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>181.7040</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>000004.SZ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>11.30</td>\n",
|
||||
" <td>11.35</td>\n",
|
||||
" <td>11.07</td>\n",
|
||||
" <td>11.08</td>\n",
|
||||
" <td>11.27</td>\n",
|
||||
" <td>-0.19</td>\n",
|
||||
" <td>-1.6859</td>\n",
|
||||
" <td>18056.00</td>\n",
|
||||
" <td>20248.567</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>4.0640</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>000006.SZ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>9.95</td>\n",
|
||||
" <td>10.03</td>\n",
|
||||
" <td>9.69</td>\n",
|
||||
" <td>9.95</td>\n",
|
||||
" <td>9.86</td>\n",
|
||||
" <td>0.09</td>\n",
|
||||
" <td>0.9128</td>\n",
|
||||
" <td>270369.08</td>\n",
|
||||
" <td>267758.676</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>39.7400</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>000007.SZ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>11.72</td>\n",
|
||||
" <td>11.75</td>\n",
|
||||
" <td>11.28</td>\n",
|
||||
" <td>11.44</td>\n",
|
||||
" <td>11.62</td>\n",
|
||||
" <td>-0.18</td>\n",
|
||||
" <td>-1.5491</td>\n",
|
||||
" <td>80556.00</td>\n",
|
||||
" <td>92109.366</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>8.2840</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",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>920978.BJ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>37.64</td>\n",
|
||||
" <td>38.39</td>\n",
|
||||
" <td>36.88</td>\n",
|
||||
" <td>36.90</td>\n",
|
||||
" <td>37.78</td>\n",
|
||||
" <td>-0.88</td>\n",
|
||||
" <td>-2.3293</td>\n",
|
||||
" <td>33945.04</td>\n",
|
||||
" <td>126954.937</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>1.2885</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>920981.BJ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>32.20</td>\n",
|
||||
" <td>32.29</td>\n",
|
||||
" <td>31.75</td>\n",
|
||||
" <td>31.96</td>\n",
|
||||
" <td>32.07</td>\n",
|
||||
" <td>-0.11</td>\n",
|
||||
" <td>-0.3430</td>\n",
|
||||
" <td>8237.16</td>\n",
|
||||
" <td>26301.206</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>1.4343</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>920982.BJ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>233.00</td>\n",
|
||||
" <td>238.49</td>\n",
|
||||
" <td>232.10</td>\n",
|
||||
" <td>233.70</td>\n",
|
||||
" <td>234.80</td>\n",
|
||||
" <td>-1.10</td>\n",
|
||||
" <td>-0.4685</td>\n",
|
||||
" <td>5210.09</td>\n",
|
||||
" <td>122452.646</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>4.2831</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>920985.BJ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>7.32</td>\n",
|
||||
" <td>7.35</td>\n",
|
||||
" <td>7.17</td>\n",
|
||||
" <td>7.19</td>\n",
|
||||
" <td>7.30</td>\n",
|
||||
" <td>-0.11</td>\n",
|
||||
" <td>-1.5068</td>\n",
|
||||
" <td>35174.30</td>\n",
|
||||
" <td>25350.257</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>1.6280</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>920992.BJ</th>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>17.33</td>\n",
|
||||
" <td>17.60</td>\n",
|
||||
" <td>17.29</td>\n",
|
||||
" <td>17.39</td>\n",
|
||||
" <td>17.38</td>\n",
|
||||
" <td>0.01</td>\n",
|
||||
" <td>0.0575</td>\n",
|
||||
" <td>6991.87</td>\n",
|
||||
" <td>12193.445</td>\n",
|
||||
" <td>20251231</td>\n",
|
||||
" <td>1.4932</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"<p>5458 rows × 12 columns</p>\n",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"execution_count": 51,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 51
|
||||
}
|
||||
],
|
||||
"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
|
||||
}
|
||||
1157
notebook/indicator.ipynb
Normal file
1157
notebook/indicator.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -1,131 +0,0 @@
|
||||
import marimo
|
||||
|
||||
__generated_with = "0.19.6"
|
||||
app = marimo.App(width="full", auto_download=["ipynb"], sql_output="pandas")
|
||||
|
||||
|
||||
@app.cell
|
||||
def _():
|
||||
import marimo as mo
|
||||
return (mo,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _():
|
||||
import urllib
|
||||
import sqlalchemy
|
||||
|
||||
host = "81.71.3.24"
|
||||
port = 6785
|
||||
username = "leopard"
|
||||
password = urllib.parse.quote_plus("9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X")
|
||||
database = "leopard_dev"
|
||||
engine = sqlalchemy.create_engine(f"postgresql://{username}:{password}@{host}:{port}/{database}")
|
||||
return (engine,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(engine, mo):
|
||||
dailies_df = mo.sql(
|
||||
f"""
|
||||
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
|
||||
from leopard_daily daily
|
||||
left join leopard_stock stock on stock.id = daily.stock_id
|
||||
where stock.code = '000001.SZ'
|
||||
and daily.trade_date between '2024-01-01 00:00:00' and '2025-12-31 23:59:59'
|
||||
order by daily.trade_date
|
||||
""",
|
||||
engine=engine
|
||||
)
|
||||
return (dailies_df,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(dailies_df):
|
||||
import pandas as pd
|
||||
|
||||
dailies_df["trade_date"] = pd.to_datetime(dailies_df["trade_date"], format='%Y-%m-%d')
|
||||
dailies_df.set_index("trade_date", inplace=True)
|
||||
dailies_df
|
||||
return
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(dailies_df):
|
||||
import talib
|
||||
|
||||
dailies_df['sma30'] = talib.SMA(dailies_df['Close'], timeperiod=30)
|
||||
dailies_df['sma60'] = talib.SMA(dailies_df['Close'], timeperiod=60)
|
||||
dailies_df['sma120'] = talib.SMA(dailies_df['Close'], timeperiod=120)
|
||||
|
||||
macd, signal, hist = talib.MACD(dailies_df["Close"], fastperiod=10, slowperiod=20, signalperiod=9)
|
||||
dailies_df['macd'] = macd
|
||||
dailies_df['signal'] = signal
|
||||
dailies_df['hist'] = hist
|
||||
|
||||
target_dailies_df = dailies_df.loc['2025-01-01':'2025-12-31']
|
||||
target_dailies_df
|
||||
return (target_dailies_df,)
|
||||
|
||||
|
||||
@app.cell
|
||||
def _(target_dailies_df):
|
||||
target_dailies_df.reset_index(inplace=True)
|
||||
target_dailies_df_inc = target_dailies_df[target_dailies_df["Close"] > target_dailies_df["Open"]]
|
||||
target_dailies_df_dec = target_dailies_df[target_dailies_df["Close"] < target_dailies_df["Open"]]
|
||||
return target_dailies_df_dec, target_dailies_df_inc
|
||||
|
||||
|
||||
@app.cell
|
||||
def daily_chart(
|
||||
target_dailies_df,
|
||||
target_dailies_df_dec,
|
||||
target_dailies_df_inc,
|
||||
):
|
||||
from bokeh.io import show, output_notebook
|
||||
from bokeh.layouts import column
|
||||
from bokeh.plotting import figure
|
||||
|
||||
output_notebook()
|
||||
|
||||
width = 1200
|
||||
up_color = "black"
|
||||
down_color = "grey"
|
||||
|
||||
price_figure = figure(width=width, height=400, tools='pan,wheel_zoom,box_zoom,reset')
|
||||
|
||||
price_figure.min_border = 0
|
||||
|
||||
x_padding = 1
|
||||
y_padding = 10
|
||||
price_figure.x_range.bounds = (min(target_dailies_df.index) - x_padding, max(target_dailies_df.index) + x_padding)
|
||||
price_figure.y_range.bounds = (min(target_dailies_df['Low']) - y_padding, max(target_dailies_df['High']) + y_padding)
|
||||
price_figure.xaxis.major_label_overrides = {i: date.strftime('%Y-%m-%d') for i, date in zip(target_dailies_df.index, target_dailies_df['trade_date'])}
|
||||
price_figure.segment(target_dailies_df.index, target_dailies_df['High'], target_dailies_df.index, target_dailies_df['Low'], color='black')
|
||||
price_figure.vbar(target_dailies_df_inc.index, 0.6, target_dailies_df_inc['Open'], target_dailies_df_inc['Close'], color=up_color)
|
||||
price_figure.vbar(target_dailies_df_dec.index, 0.6, target_dailies_df_dec['Open'], target_dailies_df_dec['Close'], color=down_color)
|
||||
price_figure.line(target_dailies_df.index, target_dailies_df['sma30'], color='orange')
|
||||
price_figure.line(target_dailies_df.index, target_dailies_df['sma60'], color='red')
|
||||
# 控制图表只能放大不能缩小
|
||||
macd_figure = figure(width=width, height=200, tools='pan,wheel_zoom,box_zoom,reset')
|
||||
macd_figure.x_range.bounds = (min(target_dailies_df.index) - x_padding, max(target_dailies_df.index) + x_padding)
|
||||
macd_figure.y_range.bounds = (min(target_dailies_df['macd']) - y_padding, max(target_dailies_df['macd']) + y_padding)
|
||||
macd_figure.line(target_dailies_df.index, target_dailies_df['macd'], color='orange')
|
||||
macd_figure.line(target_dailies_df.index, target_dailies_df['signal'], color='red')
|
||||
# Add MACD histogram bars for positive and negative values
|
||||
macd_positive = target_dailies_df[target_dailies_df['macd'] > 0]
|
||||
macd_negative = target_dailies_df[target_dailies_df['macd'] < 0]
|
||||
|
||||
macd_figure.vbar(macd_positive.index, 0.6, 0, macd_positive['macd'], color=up_color)
|
||||
macd_figure.vbar(macd_negative.index, 0.6, 0, macd_negative['macd'], color=down_color)
|
||||
|
||||
# Add zero line
|
||||
macd_figure.line(target_dailies_df.index, [0] * len(target_dailies_df), color='black', line_dash='dashed')
|
||||
# show(price_figure)
|
||||
# show(macd_figure)
|
||||
show(column(price_figure, macd_figure))
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
72
notebook/sql2dataframe.ipynb
Normal file
72
notebook/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
|
||||
}
|
||||
82
notebook/sqlalchemy.ipynb
Normal file
82
notebook/sqlalchemy.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -4,10 +4,13 @@ version = "0.1.0"
|
||||
description = "Stock analysis"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
"adata>=2.9.5",
|
||||
"akshare>=1.18.20",
|
||||
"backtesting~=0.6.5",
|
||||
"baostock>=0.8.9",
|
||||
"duckdb>=1.4.4",
|
||||
"jupyter~=1.1.1",
|
||||
"jupyter-bokeh>=4.0.5",
|
||||
"marimo>=0.19.6",
|
||||
"matplotlib~=3.10.8",
|
||||
"mplfinance>=0.12.10b0",
|
||||
"pandas~=2.3.3",
|
||||
@@ -18,13 +21,5 @@ dependencies = [
|
||||
"ta-lib>=0.6.8",
|
||||
"tabulate>=0.9.0",
|
||||
"tqdm>=4.67.1",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"mcp>=1",
|
||||
"openai>=2.16.0",
|
||||
"pydantic>=2",
|
||||
"pydantic-ai>=1.48.0",
|
||||
"ruff>=0.14.14",
|
||||
"tushare>=1.4.24",
|
||||
]
|
||||
|
||||
94
sql/initial.sql
Normal file
94
sql/initial.sql
Normal file
@@ -0,0 +1,94 @@
|
||||
CREATE TABLE stock
|
||||
(
|
||||
code varchar not null,
|
||||
name varchar not null,
|
||||
fullname varchar,
|
||||
industry varchar,
|
||||
listed_date date,
|
||||
market varchar,
|
||||
exchange varchar,
|
||||
primary key (code)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE daily
|
||||
(
|
||||
code varchar not null,
|
||||
trade_date date not null,
|
||||
open double,
|
||||
close double,
|
||||
high double,
|
||||
low double,
|
||||
previous_close double,
|
||||
turnover double,
|
||||
volume integer,
|
||||
price_change_amount double,
|
||||
factor double,
|
||||
primary key (code, trade_date)
|
||||
);
|
||||
|
||||
CREATE TABLE finance_indicator
|
||||
(
|
||||
code varchar not null,
|
||||
year integer not null,
|
||||
accounts_payable double,
|
||||
accounts_payable_to_total_assets_ratio double,
|
||||
accounts_receivable double,
|
||||
accounts_receivable_to_total_assets_ratio double,
|
||||
accounts_receivable_turnover double,
|
||||
capital_surplus double,
|
||||
cash_and_cash_equivalents double,
|
||||
cash_and_cash_equivalents_to_total_assets_ratio double,
|
||||
cash_flow_adequacy_ratio double,
|
||||
cash_flow_from_financing_activities double,
|
||||
cash_flow_from_investing_activities double,
|
||||
cash_flow_from_operating_activities double,
|
||||
cash_flow_ratio double,
|
||||
cash_reinvestment_ratio double,
|
||||
current_assets double,
|
||||
current_assets_to_total_assets_ratio double,
|
||||
current_liabilities double,
|
||||
current_liabilities_to_total_assets_ratio double,
|
||||
current_liabilities_to_total_liabilities_ratio double,
|
||||
current_ratio double,
|
||||
days_accounts_receivable_turnover double,
|
||||
days_fixed_assets_turnover double,
|
||||
days_inventory_turnover double,
|
||||
days_total_assets_turnover double,
|
||||
earnings_per_share double,
|
||||
fixed_assets double,
|
||||
fixed_assets_to_total_assets_ratio double,
|
||||
fixed_assets_turnover double,
|
||||
goodwill double,
|
||||
goodwill_to_total_assets_ratio double,
|
||||
inventory double,
|
||||
inventory_to_total_assets_ratio double,
|
||||
inventory_turnover double,
|
||||
liabilities_to_total_assets_ratio double,
|
||||
long_term_funds_to_fixed_assets_ratio double,
|
||||
long_term_liabilities double,
|
||||
long_term_liabilities_to_total_assets_ratio double,
|
||||
long_term_liabilities_to_total_liabilities_ratio double,
|
||||
net_cash_flow_from_operating_activities double,
|
||||
net_profit double,
|
||||
net_profit_margin double,
|
||||
operating_cost double,
|
||||
operating_expenses double,
|
||||
operating_gross_profit_margin double,
|
||||
operating_profit double,
|
||||
operating_profit_margin double,
|
||||
operating_revenue double,
|
||||
operating_safety_margin_ratio double,
|
||||
quick_ratio double,
|
||||
return_on_assets double,
|
||||
return_on_equity double,
|
||||
shareholders_equity double,
|
||||
shareholders_equity_to_total_assets_ratio double,
|
||||
surplus_reserve double,
|
||||
total_assets double,
|
||||
total_assets_turnover double,
|
||||
total_liabilities double,
|
||||
total_share_capital double,
|
||||
undistributed_profit double,
|
||||
primary key (code, year)
|
||||
)
|
||||
Reference in New Issue
Block a user