今日计划:
1、gui框架,回测主体界面,实盘界面框架。
2、走通回测结果展示。
把回测框架搭了一下:
投资理念
昨天我在星球发了一些期货大神的经验总结,一个星友发出了灵魂考问:
什么是正确的逻辑,什么是正确的理念和正确的方法?
关注我的老朋友知道,我是把投资当成科学来研究的,不会上升到玄学的领域。我在这里尝试回复一下。
逻辑,理念和方法,加总起来是一个叫“投资体系”的东西。这是认知层面的东西,不具体到某一个策略或者操作手法,这都是“术”的层面。
很喜欢塔勒布关于不确定的研究,里面的“杠铃策略”尤是。
一端代表极保守,另一个代表追求高风险高收益。
有同学说,期货风险多高呀,老师真要实战嘛。我的回应的,很多人也是这么看股票的。风险第一位是对的,但知道自己在做什么,边界在哪里更重要。
我说一个反脆弱的财富增长“体系”。比如你有500万的自由现金流,你该如何投资?或者做资产配置?股票?股票还是房产。
90%做大类资产配置,股债平衡,追求长期10%的年化收益。拿10%(约50万)可以配置高风险高收益的投资,比如期货。这个10%的50万,假如20倍的杠杆,可以分成10份,一次投资成功翻一番。
你说如果10次都输了呢?450万的本金,长期来看,下一期可以补充高风险投资本金需要,要不会带来巨大的心理压力和实际的本金损失,机会来临,就可能逆风翻盘。
这是道的层面的东西,知道自己在做什么很关键。
高手从来不是赌,是构建系统,“先胜而后求战”。
量化调研
调研了一下国内几个开源量化软件或平台。
总结下来:
1、数据平台,给普通用户做数据服务的。传统金融软件就是日K线+技术指标,或者支持一些表达式宏。想做更复杂的事情,不太方便。高级用户有自己导出,或者自己分析的需求,但金融数据库相对普通用户又太贵,因此有了一些量化数据分析平台。
2、策略开发:在线量化平台,quantopian模式,多数都转私募或者服务B端了。含数据服务,回测系统及实盘对接。——这里的难点当然还是策略,平台也做培训服务。
3、交易端,主要是期货CTA。从服务私募到服务高级用户,to B到to 大C的逻辑,外加知识付费为主。
数据平台是一个细致的体力活,数据是量化的起点,但离量化还有距离。一些数据平台也会按一些指标跑出规律,甚至给出回测的分析。
在线量化平台,数据为量化策略服务。难点在于有能力写策略的人,往往不那么需要这样一个平台,而且还是速度慢,不灵活以及策略安全性的问题。这可能也是quantopian不长久的原因吧。
交易离钱最近,直命痛点。
规划中的平台,应该这样——以实盘为导向:
1、数据,不用大而全,够用就好,准备一些有代表性的,用户可以方便的更新,导入与管理。
2、策略开发,足够高效与易用。很多平台开发策略,调试策略相当费劲,而且还需要持续担心是否出bug。内置大量结构化、模块化的算子,因子挖掘,组合优化,参数调优等等。
3、实盘。按需对接,比如相对容易的,期货。
4、有gui本地运行,交易还是需要干预的,不是所有人的都会写代码。
小结
七年之约,只是开始。
践行长期主义。
万物之中,希望至美。
人工智能与金融投资,都是长坡厚雪,且还是为数不多,可以满足个人英雄主义情结的地方。
走,一起赶路吧。
今日工作:
1、因子表达式重构
2、整合ffn代码,去掉pyfolio, quantstats。
星球的合伙人计划,已有三名位同学入选,本周若超过10位,将组织第一次例会,探讨平台发展计划,答疑等。
最近做了一些调研,实盘对接做得好的几家,主要集中在期货量化。因为期货CTA本身就是合规,甚至是鼓励的。除了加密货币,最适合量化的领域是期货的CTA或者外汇的RA。
星球很多同学反馈,代码用起来有难度,其实是的,读别人的代码本身就有难度,何况叠加对量化、金融、人工智能的理解。
因此,后续我尽可能把易用性做出来,产品化、服务化。
系统代码已经发布至星球:
因子表达式重构的原因:
之前考虑到rank这个函数,需要截面排序,因此需要全体数据进行运算之后,才能rank,因此引入了group_by(‘date’),当然也引入了调试的复杂性。从帮助大家简单理解的角度,我决定去掉groupby。
Duckdbloader使用上没有变化:
在计算因子表达式时,单个dataframe循环计算:
def load(self, fields=None, names=None): dfs = self._load_dfs() # df = self._reset_index(df) if not fields or not names or len(fields) != len(names): return self._concat_dfs(dfs) else: # 截面rank需要 dfs_expr = [] for df in tqdm(dfs): for field, name in tqdm(zip(fields, names)): df[name] = calc_expr(df, field) dfs_expr.append(df) df = self._concat_dfs(dfs_expr) # todo 如果需要支持截面rank,逻辑加在这里 return df
这里,表达式函数的实现就可以非常简单。
输入是pd.Series以及其它参数:
def shift(se: pd.Series, N): return se.shift(N) def roc(se: pd.Series, N): return se / shift(se, N) - 1
rolling的函数实现也变得简单:
import numpy as np import pandas as pd from scipy.stats import percentileofscore def rolling(se, N, func): ind = getattr(se.rolling(window=N), func)() return ind def sum(se: pd.Series, N): return rolling(se, N, 'sum') def max(se, N): return rolling(se, N, 'max') def min(se, N): return rolling(se, N, 'min') def std(se, N): return rolling(se, N, 'std') def avg(se, N): se = rolling(se, N, 'mean') return se def mean(se, N): return avg(se, N) def idxmax(se, N): return rolling(se, N, 'argmax') def idxmin(se, N): return rolling(se, N, 'argmin') def ts_rank(se, N): return se.rolling(N).apply(lambda x: percentileofscore(x, x[-1]) / len(x)) def _zscore(se): return se - se.mean() / se.std() def zscore(se: pd.Series, N): return se.rolling(window=N).apply(lambda x: _zscore(x)) def _slope(x): try: x = x / x.iloc[0] # 这里做了一个“归一化” slope = np.polyfit(range(len(x)), x, 1)[0] return slope except: return -1 def slope(se, N): result = se.rolling(N, min_periods=2).apply(lambda x: slope(x)) return result def quantile(se, N, qscore): return se.rolling(N, min_periods=1).quantile(qscore) def bias(se, N): return se.rolling(N).apply(lambda x: x / x.mean()) def _qcut(se: pd.Series, quantiles, N): if len(se) < 3: return return pd.qcut(se, quantiles, labels=range(0, N), duplicates='drop').astype('float') def qcut(se: pd.Series, N): quantiles = [step / 100 for step in range(0, 100, int(100 / N))] if len(quantiles) <= N: quantiles.append(1) labels = se.rolling(N).apply( lambda sub_se: _qcut(sub_se, quantiles, N)) return labels
本次重构没有用到talib,列为todo。
验证alpha158,没有问题:
借用了ffn计算指标的功能,取代了quantstats。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/103860
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!