Initial commit: cc-cursor 全链路量化研究平台
7 Sprints 全部完成: Sprint 0: 基础设施 (DataManager + MariaDB) Sprint 1: 因子引擎 (34因子/12分类) Sprint 2: VectorBT 回测 (5策略+截面) Sprint 3: Optuna 优化 (+Walk-Forward) Sprint 4: ML 模型 (LightGBM+CatBoost) Sprint 5: Qwen 情绪因子 (三源新闻+日期对齐) Sprint 6: Agent 系统 (4Agent+日报.md/.html) 生产加固 (15项): Tushare双源fallback, SSH自动恢复, pool_pre_ping, save_daily先删后插, load_dotenv绝对路径, 日报5d/20d修复, RiskAgent改上证指数, 昨日对比+数据截止, mac_report utf8mb4, CLAUDE-*.md 9条已知Bug, demo全参数化, djapi数据源归一化, indexDatas API修正 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
import sys
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.response import Response
|
||||
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
|
||||
|
||||
from .stock.stock_utils import viewFunc_tsCodeAndDate, viewFunc_singleParam
|
||||
from .stock.stock_basic import getStockBasic, getStockListByIndustry, getStockInfo
|
||||
from .stock.getStockParam import getStockParam
|
||||
from .stock.getStockEp import getStockEp_ttm, get_quarterly_eps
|
||||
from .stock.getIndexs import get_index_daily_data, get_index_by_name
|
||||
from .stock.stockMargin import getStockMargin, getDailyMargin
|
||||
from .stock.getStockFina import get_finance_data_range
|
||||
from .stock.getStockDiv2 import analyze_stock_dividend_and_price
|
||||
from .stock.xwlbDaily import get_xwlb, get_xwlb_fine
|
||||
from .stock.getDivData_AK import get_akshare_dividend_yield
|
||||
from .serializers import (
|
||||
StockDailySerializer, StockInfoSerializer, IndustryStockSerializer,
|
||||
StockParamSerializer, StockEpSerializer, QuarterlyEpsSerializer,
|
||||
IndexInfoSerializer, IndexDailySerializer, MarginDailySerializer,
|
||||
StockMarginSerializer, FinanceDataSerializer, DividendSerializer,
|
||||
XwlbNewsSerializer,
|
||||
)
|
||||
|
||||
# === 通用参数定义(复用) ===
|
||||
_PARAM_TSCODE = OpenApiParameter(name='tscode', type=str, default='000001.SZ',
|
||||
description='股票代码,如 000001.SZ')
|
||||
_PARAM_INDEX_CODE = OpenApiParameter(name='tscode', type=str, default='000001.SH',
|
||||
description='指数代码,如 000001.SH=上证指数, 399001.SZ=深证成指, 399006.SZ=创业板指')
|
||||
_PARAM_START = OpenApiParameter(name='start_date', type=str, default='20200101',
|
||||
description='起始日期 yyyyMMdd')
|
||||
_PARAM_END = OpenApiParameter(name='end_date', type=str, default='20251231',
|
||||
description='结束日期 yyyyMMdd')
|
||||
_PARAM_INDEX_NAME = OpenApiParameter(name='index_name', type=str, default='沪深300',
|
||||
description='指数名称,如 沪深300、上证50')
|
||||
_PARAM_INDUSTRY = OpenApiParameter(name='industry', type=str, required=True,
|
||||
description='行业名称,如 银行、半导体')
|
||||
_PARAM_TRADE_DATE = OpenApiParameter(name='trade_date', type=str,
|
||||
description='交易日期 yyyyMMdd')
|
||||
_PARAM_EXCHANGE_ID = OpenApiParameter(name='exchange_id', type=str,
|
||||
description='交易所代码 SSE/SZSE')
|
||||
|
||||
|
||||
@extend_schema(
|
||||
responses={200: OpenApiTypes.STR},
|
||||
description='返回服务器 Python 版本',
|
||||
tags=['系统'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def python_version(request):
|
||||
return HttpResponse(f"Python Version: {sys.version}")
|
||||
|
||||
|
||||
@extend_schema(exclude=True)
|
||||
@api_view(['GET'])
|
||||
def home(request):
|
||||
return render(request, 'home.html')
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: StockDailySerializer(many=True)},
|
||||
description='获取个股日线行情数据(开高低收、成交量、成交额)',
|
||||
tags=['行情'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def stockbasic(request):
|
||||
return viewFunc_tsCodeAndDate(request, getStockBasic)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_INDUSTRY],
|
||||
responses={200: IndustryStockSerializer(many=True)},
|
||||
description='按申万行业分类查询成分股列表',
|
||||
tags=['基础数据'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def industrys(request):
|
||||
return viewFunc_singleParam(request, getStockListByIndustry, param_name='industry')
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE],
|
||||
responses={200: StockInfoSerializer()},
|
||||
description='获取个股基本信息(名称、行业、上市日期、交易所等)',
|
||||
tags=['基础数据'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def stockInfo(request):
|
||||
return viewFunc_singleParam(request, getStockInfo, param_name='tscode')
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: StockParamSerializer(many=True)},
|
||||
description='获取个股每日参数(市值、PE/PB/PS、换手率等)',
|
||||
tags=['行情'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def stockparam(request):
|
||||
return viewFunc_tsCodeAndDate(request, getStockParam)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: StockEpSerializer(many=True)},
|
||||
description='获取个股 TTM 每股收益(EPS)',
|
||||
tags=['财务'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def stockep(request):
|
||||
return viewFunc_tsCodeAndDate(request, getStockEp_ttm)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: QuarterlyEpsSerializer(many=True)},
|
||||
description='获取个股季度每股收益(EPS),按财报日期对齐',
|
||||
tags=['财务'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def quarterlyEps(request):
|
||||
return viewFunc_tsCodeAndDate(request, get_quarterly_eps)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_INDEX_NAME],
|
||||
responses={200: IndexInfoSerializer()},
|
||||
description='按名称模糊查询指数基本信息',
|
||||
tags=['指数'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def indexByName(request):
|
||||
index_name = request.GET.get('index_name', '沪深300')
|
||||
if not index_name:
|
||||
return Response({'error': '缺少 index_name 参数'}, status=400)
|
||||
try:
|
||||
data = get_index_by_name(index_name)
|
||||
dict_data = data.to_dict(orient='records')
|
||||
return Response(dict_data)
|
||||
except ImportError:
|
||||
return Response({'error': '模块不存在'}, status=500)
|
||||
except Exception as e:
|
||||
return Response({'error': str(e)}, status=500)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_INDEX_CODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: IndexDailySerializer(many=True)},
|
||||
description='获取指数日线行情数据(含 PE/PB/市值/换手率等扩展指标)',
|
||||
tags=['指数'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def indexDatas(request):
|
||||
return viewFunc_tsCodeAndDate(request, get_index_daily_data)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: StockMarginSerializer(many=True)},
|
||||
description='获取个股融资融券明细数据',
|
||||
tags=['融资融券'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def stockMargin(request):
|
||||
return viewFunc_tsCodeAndDate(request, getStockMargin)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TRADE_DATE, _PARAM_START, _PARAM_END, _PARAM_EXCHANGE_ID],
|
||||
responses={200: MarginDailySerializer(many=True)},
|
||||
description='获取每日融资融券汇总数据(按交易所)',
|
||||
tags=['融资融券'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def dailyMargin(request):
|
||||
trade_date = request.GET.get('trade_date', None)
|
||||
start_date = request.GET.get('start_date', None)
|
||||
end_date = request.GET.get('end_date', None)
|
||||
exchange_id = request.GET.get('exchange_id', None)
|
||||
|
||||
try:
|
||||
data = getDailyMargin(trade_date=trade_date, start_date=start_date,
|
||||
end_date=end_date, exchange_id=exchange_id)
|
||||
dict_data = data.to_dict(orient='records')
|
||||
return Response(dict_data)
|
||||
except ImportError:
|
||||
return Response({'error': '模块不存在'}, status=500)
|
||||
except Exception as e:
|
||||
return Response({'error': str(e)}, status=500)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: FinanceDataSerializer(many=True)},
|
||||
description='获取个股财务报表分析数据(资产负债表+利润表+现金流,含运营/资产/负债/回报率指标)',
|
||||
tags=['财务'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def getFinaData(request):
|
||||
return viewFunc_tsCodeAndDate(request, get_finance_data_range)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: DividendSerializer(many=True)},
|
||||
description='获取个股股息率数据(含 TTM 分红、收盘价、股息率)',
|
||||
tags=['分红'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def getDivData(request):
|
||||
return viewFunc_tsCodeAndDate(request, analyze_stock_dividend_and_price)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_TSCODE, _PARAM_START, _PARAM_END],
|
||||
responses={200: DividendSerializer(many=True)},
|
||||
description='获取个股股息率数据(akshare 数据源,无需 token)',
|
||||
tags=['分红'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def getDivDataAkshare(request):
|
||||
return viewFunc_tsCodeAndDate(request, get_akshare_dividend_yield)
|
||||
|
||||
|
||||
def _xwlb_view(request, data_func):
|
||||
start_date = request.GET.get('start_date', None)
|
||||
end_date = request.GET.get('end_date', None)
|
||||
try:
|
||||
data = data_func(start_date=start_date, end_date=end_date)
|
||||
dict_data = data.to_dict(orient='records')
|
||||
status = "success" if dict_data else "Error"
|
||||
return Response({"status": status, "data": {"news": dict_data}})
|
||||
except ImportError:
|
||||
return Response({'error': '模块不存在'}, status=500)
|
||||
except Exception as e:
|
||||
return Response({'error': str(e)}, status=500)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_START, _PARAM_END],
|
||||
responses={200: XwlbNewsSerializer(many=True)},
|
||||
description='获取新闻联播原始识别文本(ASR 转写结果)',
|
||||
tags=['新闻联播'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def xwlbNews(request):
|
||||
return _xwlb_view(request, get_xwlb)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
parameters=[_PARAM_START, _PARAM_END],
|
||||
responses={200: XwlbNewsSerializer(many=True)},
|
||||
description='获取新闻联播精编内容(AI 分割+标题提取后的独立新闻)',
|
||||
tags=['新闻联播'],
|
||||
)
|
||||
@api_view(['GET'])
|
||||
def xwlbFine(request):
|
||||
return _xwlb_view(request, get_xwlb_fine)
|
||||
Reference in New Issue
Block a user