第一问答网

 找回密码
 立即注册
查看: 83|回复: 0

2023年投资思路&django-ninja框架导入

[复制链接]

5

主题

13

帖子

25

积分

新手上路

Rank: 1

积分
25
发表于 2023-1-17 00:41:05 | 显示全部楼层 |阅读模式
今天我们——原创文章第151篇,专注“个人成长与财富自由、世界运作的逻辑,AI量化投资"。2023年新年第一天。
昨天挥别2022年,迎接2023年。的计划,把投资计划变成一个系统——所谓系统就是“每天都会做的事情”。优先做主动投资相关的事情。

按昨天的规划:主动投资能力、技术能力、写作(社群)。

01 投资篇
我的大类资产组合的年度绝对收益-7%。就是大类资产配置、动态再平衡的结果,年度最大回撤差不多在-9%以内。

集思录有人晒出了2022年的投资总结:绝对收益-8%。转债收益9%,A股-2%,境外-33%。



这位兄弟转债收益(双低轮动策略,这个策略比较容易量化,震荡市比较稳健 ,上升市容易错过涨势)不错,A股的投资相对收益也算高了,毕竟大盘下跌了15%。他主要的亏损在投资了美股的对冲基金。
关于“折腾不如躺平”的逻辑。



这里有几个大结论有点意思:
单一资产的时间序列择时,能够显著降低最大回撤,但不能提供更高的投资收益。
这个结果符合逻辑,但反很多人的直觉。当然,这里它所指的序列择时,是“均线择时”。就是均线择时可以有效降低回撤,但无法提供额外的alpha。




我在前面的文章也提及过,单资产择时是投资里最难的,很多人迷恋追涨杀跌做波段,这几乎是个不可能完成的任务,但确实能有效降低回撤。
多资产的动量横截面择时,则正好相反:能够提供高于多资产均值的投资收益,但最大回撤的增幅会更大。





单资产择时,增加资产类别,长期看不能有效提升收益,收益本质上是资产本身的beta决定的。——当然,这里的数据分析更多是通过成熟市场得出,这应该就是资产配置是归宿。A股现在还是散户市,alpha还是有的
找到优质的长期向上的资产类别,大类资产类别里,找到长期跑赢市场基准的指数,比如消费、医药,科技等。——这就是我大类资产配置的核心底层逻辑。

股票的经营业绩最多提供10-15%的长期年化回报;如果想要进一步提高投资收益,则必须赚取波动的钱 —— 也就是,必须要短炒。
另一个网友的总结,他的绝对收益是-2.7%。

2016年36%;
2017年22%;
2018年17%;
2019年22%;
2020年25.3%;
2021年38.4%;
2022年-2.7%。
这绝对是一个高手了,今年的市场也没有赚到钱。如下是他的2023年计划。
2023年将全力可转债!策略依然是以双低为基础的多因子轮动策略,同时剔除一些低波动的转债、有违约可能性的转债。
理由如下:
1、疫情即将过去,下一步必然拼经济;
2、双低可转债估值目前不算贵,处于相对合理的状态,特别是在2022年里算是相对低点;
3、市场涨跌难以预测,但可转债至少还有债性保底,在分散分散再分散的策略下,这是个概率占优的游戏,长期按策略轮动明显是具有相对收益的。
从估值,动量,概率的角度,我认同这个策略——双低为基础的多因子可转债轮动策略。后续我来量化建模。

02  技术篇
从drf切换到django-ninja。

drf是一个传统以model驱动的rest框架,可以对一个模型进行CURD。但fastapi给了我一个提示,现代后端系统不完全是一个rest标准,不是把model当成资源这么简单,会涉及到缓存、nosql,分布式等等。传统rest api应用起来挺麻烦。
django-ninja与fastapi“长得”几乎一样,就是受fastapi启发,但可以与django原生生成整合到一起,即可以获得django的orm, admin的优势,同时还可以获得fastapi的异步,swagger,pydantic的数据校验能力。




api本身就是一个json_response,对一个dict字典结构进行序列化后返回的过程。ninja类似fastapi做了入参与出参自动解析与校验的工作,可以省下我们一些工作量,另外就是swagger的界面整合,还是router路由等。

当然api工作本身有一个权限与认证的过程,这个相对更加重要。现在前后端分离不可能使用session-auth,这个基本不用了,主要是jwt的token认证机制。
今天我们主要搞搞基本django-ninja的jwt机制。
from ninja.security import HttpBearer


class AuthBearer(HttpBearer):
    def authenticate(self, request, token):
        if token == "supersecret":
            return token
header里需要带 Authorization字段, Bearer TOKEN。

curl -X 'GET' \
  'http://127.0.0.1:8000/api/common/test_auth' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer aaa'这个HttpBearer是会从header里取出Authorization后面的TOKEN。

这里的auth可以是任意可执行的函数,比如校验ip的黑白名单等。还有api key的场景,无论是在query key,header里或者cookie里,ninja都有一些支持,其实自己实现也不复杂。
https://github.com/jmwri/simplejwt
simplejwt封装了encode, decode功能。
from datetime import datetime

from simplejwt.jwt import Jwt, decode

SECRET_KEY = '123456'
# token 有效时间 时 分 秒
TOKEN_LIFETIME = 12 * 60 * 60


class JwtUtils:
    @staticmethod
    def get_token(payload):
        time_now = int(datetime.now().timestamp())
        valid_to = time_now + TOKEN_LIFETIME
        jwt = Jwt(secret=SECRET_KEY, payload=payload, valid_to=valid_to)
        return jwt.encode()

    @staticmethod
    def get_payload(token):
        return decode(SECRET_KEY, token)[1]


    @staticmethod
    def is_timeout(payload):
        time_now = int(datetime.now().timestamp())
        if payload['exp'] < time_now:
            return True
        else:
            return False


if __name__ == '__main__':
    token = JwtUtils.get_token({'username': 'admin'})
    print(token)
    payload = JwtUtils.get_payload(token)
    print(payload)
    print(JwtUtils.is_timeout(payload))

本质上,就是把一个字典进行加密,使用同一个SECRET_KEY可以对数据进行解密,取出数据。
使用如下AuthBearer可以给任意一个api请求做jwt校验,token是自动获取的,其实就是从header里的meta取出authorization里的token。然后写自己的检验逻辑即可。若返回False就是一个401的错误。
class AuthBearer(HttpBearer):
    def authenticate(self, request, token):
        payload = JwtUtils.get_payload(token)
        username = payload.get('username')
        print(username)
        # if username == 'admin':
        #    return False
        return True校验成功之后,类似session机制,需要拿到current_user对象,session验证是把对象保存在session里,而jwt模式下,可以从token里解出user_info。

@router.get("/test_auth", auth=AuthBearer())
def bearer(request):
    user_info = get_user_info_from_token(request)
    return {'message': 'test_auth正常使用', 'user_info': user_info}
get_user_info_form_token的代码如下:

def get_user_info_from_token(request):
    token = request.META.get("HTTP_AUTHORIZATION")
    token = token.split(" ")[1]
    user_info = JwtUtils.get_payload(token)
    return user_info
其实框架只是把一些例行性的功能做了封装。

在熟悉机制之后用比较好,省不少模板代码。但从学习的角度,还是自己从更基础的代码开始实现会更好掌握。
小结:

投资的角度,主动投资并不容易。A股 alpha有些机会,可转债双低轮动也许有机会。前后端分享django+ ninja是个不错的选择。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|第一问答网

GMT+8, 2025-4-20 09:22 , Processed in 0.141967 second(s), 23 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.. 技术支持 by 巅峰设计

快速回复 返回顶部 返回列表