python获取通达信可转债日线和分时数据

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 286 次浏览 • 2022-08-28 10:41 • 来自相关话题

昨天看到优矿平台公告,开始对大部分数据获取接口进行收费。
 





 
 除了优矿,还有哪些可以获取可转债日线,甚至分时tick数据呢?当然笔者压箱底里面还有很多可用数据源的。本文就简单介绍其中一个,下通达信数据源。
 
安装
使用pip安装第三方库pytdxpip install pytdx



分时数据
下面6行python代码, 就可以获取通达信的可转债分时数据。from pytdx.hq import TdxHq_API
api = TdxHq_API()
with api.connect('119.147.212.81', 7709):
data = api.get_security_bars(7, 0, '123045', 0, 240) # 123045 为转债代码 ,240 为获取 240个转债数据
df = api.to_df(data)
df=df.sort_values('datetime')
 




如果需要遍历当前最新可转债代码,需要结合前面的文章。【注意这代码会定期更新,因网站架构或者字段是不定时变动】

不过前面的接口只能读取800条数据,以一天240条数据计算,只能读取2天多的数据量,对于需要更多数据的朋友来说,肯定不够的。或者有一个办法,把上面代码写成定时任务,就可以每天收盘后自动存储对应的数据。

如果需要更多的历史数据,那么可以使用pytdx的另外一个功能,那就是使用python读取通达信本地数据文件。

先用通达信同步1分钟(或5分钟)数据到本地.
 





 
选择沪深京分钟线,当然,其他数据你也可以选择。勾选一分钟线数据或者5分钟线数据,还有日期。不过这里日期会有限制,只能下载100天的1分钟线,或者500天的5分钟线。所以如果长期需要这个数据,你可以每隔一段时间下载一次。

数据保存路径:通达信安装目录的 vipdoc 子目录比如我的通达信客户端安装在 c:\new_tdx 下,



c:\new_tdx\vipdoc\sz\lday\ 下是深圳的日k线数据
c:\new_tdx\vipdoc\sh\lday\ 下是上海的日k线数据
c:\new_tdx\vipdoc\sh\minline\ 下是上海的分钟线数据
c:\new_tdx\vipdoc\sz\minline\ 下是深圳的分钟线数据





 
如果你需要更久的历史数据,可以到网上找找,下载下来后按照下面代码读取即可。 from pytdx.reader import TdxMinBarReader
path='/home/xda/Downloads/sz128014.lc1'
reader = TdxMinBarReader()
df = reader.get_df(path)
#df.to_excel('tick.xlsx') # 导出为excel







 
得到dataframe对象后,接着可以保存为excel,数据库都很简单了。一条语句的事情。
 
可转债日线数据
 
当然,能够获取到分钟数据,对于日线数据更加不在话下了。日线数据并没有日期限制,想下多少有多少。api = TdxHq_API()
api = api.connect('119.147.212.81', 7709)
data=api.get_k_data('123045', '2020-05-01', '2022-08-26') # 123045 为可转债代码,可以替换任意代码
data.to_excel('k-line.xlsx')






 
如果想获取正股或者其他股票数据,只需要把代码替换成正股股票代码即可。

如果分钟数据还不满足,还可以使用更小粒度的tick数据。下回有空再继续介绍,敬请关注。
 







欢迎关注公众号 查看全部
昨天看到优矿平台公告,开始对大部分数据获取接口进行收费。
 

20220827005.png

 
 除了优矿,还有哪些可以获取可转债日线,甚至分时tick数据呢?当然笔者压箱底里面还有很多可用数据源的。本文就简单介绍其中一个,下通达信数据源。
 
安装
使用pip安装第三方库pytdx
pip install pytdx



分时数据
下面6行python代码, 就可以获取通达信的可转债分时数据。
from pytdx.hq import TdxHq_API
api = TdxHq_API()
with api.connect('119.147.212.81', 7709):
data = api.get_security_bars(7, 0, '123045', 0, 240) # 123045 为转债代码 ,240 为获取 240个转债数据
df = api.to_df(data)
df=df.sort_values('datetime')

 
20220827001-1.png

如果需要遍历当前最新可转债代码,需要结合前面的文章。【注意这代码会定期更新,因网站架构或者字段是不定时变动】

不过前面的接口只能读取800条数据,以一天240条数据计算,只能读取2天多的数据量,对于需要更多数据的朋友来说,肯定不够的。或者有一个办法,把上面代码写成定时任务,就可以每天收盘后自动存储对应的数据。

如果需要更多的历史数据,那么可以使用pytdx的另外一个功能,那就是使用python读取通达信本地数据文件。

先用通达信同步1分钟(或5分钟)数据到本地.
 

20220827002.png

 
选择沪深京分钟线,当然,其他数据你也可以选择。勾选一分钟线数据或者5分钟线数据,还有日期。不过这里日期会有限制,只能下载100天的1分钟线,或者500天的5分钟线。所以如果长期需要这个数据,你可以每隔一段时间下载一次。

数据保存路径:通达信安装目录的 vipdoc 子目录
比如我的通达信客户端安装在 c:\new_tdx 下,



c:\new_tdx\vipdoc\sz\lday\ 下是深圳的日k线数据
c:\new_tdx\vipdoc\sh\lday\ 下是上海的日k线数据
c:\new_tdx\vipdoc\sh\minline\ 下是上海的分钟线数据
c:\new_tdx\vipdoc\sz\minline\ 下是深圳的分钟线数据


20220827004.png

 
如果你需要更久的历史数据,可以到网上找找,下载下来后按照下面代码读取即可。
        from pytdx.reader import TdxMinBarReader
path='/home/xda/Downloads/sz128014.lc1'
reader = TdxMinBarReader()
df = reader.get_df(path)
#df.to_excel('tick.xlsx') # 导出为excel



20220827003.png


 
得到dataframe对象后,接着可以保存为excel,数据库都很简单了。一条语句的事情。
 
可转债日线数据
 
当然,能够获取到分钟数据,对于日线数据更加不在话下了。日线数据并没有日期限制,想下多少有多少。
api = TdxHq_API()
api = api.connect('119.147.212.81', 7709)
data=api.get_k_data('123045', '2020-05-01', '2022-08-26') # 123045 为可转债代码,可以替换任意代码
data.to_excel('k-line.xlsx')

20220827006.png



 
如果想获取正股或者其他股票数据,只需要把代码替换成正股股票代码即可。

如果分钟数据还不满足,还可以使用更小粒度的tick数据。下回有空再继续介绍,敬请关注。
 

20220827008.png



欢迎关注公众号

6行python代码 获取通达信的可转债分时数据

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 206 次浏览 • 2022-08-27 14:33 • 来自相关话题

6行python代码 获取通达信的可转债分时数据。from pytdx.hq import TdxHq_API
api = TdxHq_API()
with api.connect('119.147.212.81', 7709):
data = api.get_security_bars(7, 0, '123045', 0, 240) # 123045 为转债代码 ,240 为获取 240个转债数据
df = api.to_df(data)
df=df.sort_values('datetime')


点击查看大图 
 
如果需要遍历当前最新可转债代码(集思录),需要结合前面的文章。 查看全部
6行python代码 获取通达信的可转债分时数据。
from pytdx.hq import TdxHq_API
api = TdxHq_API()
with api.connect('119.147.212.81', 7709):
data = api.get_security_bars(7, 0, '123045', 0, 240) # 123045 为转债代码 ,240 为获取 240个转债数据
df = api.to_df(data)
df=df.sort_values('datetime')
20220827001-1.png
点击查看大图 
 
如果需要遍历当前最新可转债代码(集思录),需要结合前面的文章。

Ptrade 逆回购+自动申购新股可转债

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 210 次浏览 • 2022-08-24 20:03 • 来自相关话题

分享一些最基本的ptrade代码实盘例子。 持续更新,喜欢的朋友请关注本站哦。
本站所有代码均经过实盘验证。# ptrade软件-量化-回测 里,新建策略,复制全文粘贴进去,周期选分钟,再到交易里新增交易

import time

def reverse_repurchase(context):
cash = context.portfolio.cash
amount = int(cash/1000)*10
log.info(amount)
order('131810.SZ', -1*amount) # 深圳逆回购,


def ipo(context):
ipo_stocks_order()


def initialize(context):
g.flag = False
log.info("initialize g.flag=" + str(g.flag) )
run_daily(context, reverse_repurchase, '14:57')
run_daily(context, ipo, '13:30')

def before_trading_start(context, data):
pass

def handle_data(context, data):
pass

def on_order_response(context, order_list):
# 该函数会在委托回报返回时响应
log.info(order_list)
上面代码设定在13:30分申购新股,新债;
在14:57分申购深圳逆回购R-001
 
喜欢的朋友拿去,欢迎转载。
 

欢迎关注公众号
  查看全部
分享一些最基本的ptrade代码实盘例子。 持续更新,喜欢的朋友请关注本站哦。
本站所有代码均经过实盘验证。
# ptrade软件-量化-回测 里,新建策略,复制全文粘贴进去,周期选分钟,再到交易里新增交易

import time

def reverse_repurchase(context):
cash = context.portfolio.cash
amount = int(cash/1000)*10
log.info(amount)
order('131810.SZ', -1*amount) # 深圳逆回购,


def ipo(context):
ipo_stocks_order()


def initialize(context):
g.flag = False
log.info("initialize g.flag=" + str(g.flag) )
run_daily(context, reverse_repurchase, '14:57')
run_daily(context, ipo, '13:30')

def before_trading_start(context, data):
pass

def handle_data(context, data):
pass

def on_order_response(context, order_list):
# 该函数会在委托回报返回时响应
log.info(order_list)

上面代码设定在13:30分申购新股,新债;
在14:57分申购深圳逆回购R-001
 
喜欢的朋友拿去,欢迎转载。
 

欢迎关注公众号
 

Ptrade 获取当天可转债代码列表

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 212 次浏览 • 2022-08-22 18:46 • 来自相关话题

注意Ptrade版本:2022版,旧版应该不行的。
 
可以在开盘的时候获取所有可转债列表。 
 def initialize(context):
run_daily(context, get_trade_cb_list, "9:25")


def before_trading_start(context, data):
# 每日清空,避免取到昨日市场代码表
g.trade_cb_list =


def handle_data(context, data):
pass


# 获取当天可交易的可转债代码列表
def get_trade_cb_list(context):
cb_list = get_cb_list()
cb_snapshot = get_snapshot(cb_list)
# 代码有行情快照并且交易状态不在暂停交易、停盘、长期停盘、退市状态的判定为可交易代码
g.trade_cb_list = [cb_code for cb_code in cb_list if
cb_snapshot.get(cb_code, {}).get("trade_status") not in
[None, "HALT", "SUSP", "STOPT", "DELISTED"]]
log.info("当天可交易的可转债代码列表为:%s" % g.trade_cb_list)
如果需要获取可转债溢价率,评级,剩余规模,强赎等数据,可以调用我之前提供的接口。 
需要的可以关注个人星球和公众号。


欢迎关注公众号
  查看全部
注意Ptrade版本:2022版,旧版应该不行的。
 
可以在开盘的时候获取所有可转债列表。 
 
def initialize(context):
run_daily(context, get_trade_cb_list, "9:25")


def before_trading_start(context, data):
# 每日清空,避免取到昨日市场代码表
g.trade_cb_list =


def handle_data(context, data):
pass


# 获取当天可交易的可转债代码列表
def get_trade_cb_list(context):
cb_list = get_cb_list()
cb_snapshot = get_snapshot(cb_list)
# 代码有行情快照并且交易状态不在暂停交易、停盘、长期停盘、退市状态的判定为可交易代码
g.trade_cb_list = [cb_code for cb_code in cb_list if
cb_snapshot.get(cb_code, {}).get("trade_status") not in
[None, "HALT", "SUSP", "STOPT", "DELISTED"]]
log.info("当天可交易的可转债代码列表为:%s" % g.trade_cb_list)

如果需要获取可转债溢价率,评级,剩余规模,强赎等数据,可以调用我之前提供的接口。 
需要的可以关注个人星球和公众号。


欢迎关注公众号
 

Ptrade里面的 持久化 (pickle)要求 报错:

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 197 次浏览 • 2022-08-22 17:42 • 来自相关话题

关于持久化

为什么要做持久化处理

服务器异常、策略优化等诸多场景,都会使得正在进行的模拟盘和实盘策略存在中断后再重启的需求,但是一旦交易中止后,策略中存储在内存中的全局变量就清空了,因此通过持久化处理为量化交易保驾护航必不可少。

量化框架持久化处理

使用pickle模块保存股票池、账户信息、订单信息、全局变量g定义的变量等内容。

注意事项:

框架会在before_trading_start(隔日开始)、handle_data、after_trading_end事件后触发持久化信息更新及保存操作;

券商升级/环境重启后恢复交易时,框架会先执行策略initialize函数再执行持久化信息恢复操作。
 
如果持久化信息保存有策略定义的全局对象g中的变量,将会以持久化信息中的变量覆盖掉initialize函数中初始化的该变量。

1 全局变量g中不能被序列化的变量将不会被保存。
您可在initialize中初始化该变量时名字以'__'开头;

2 涉及到IO(打开的文件,实例化的类对象等)的对象是不能被序列化的;

3 全局变量g中以'__'开头的变量为私有变量,持久化时将不会被保存;
 
示例代码:class Test(object):
count = 5

def print_info(self):
self.count += 1
log.info("a" * self.count)


def initialize(context):
g.security = "600570.SS"
set_universe(g.security)
# 初始化无法被序列化类对象,并赋值为私有变量,落地持久化信息时跳过保存该变量
g.__test_class = Test()

def handle_data(context, data):
# 调用私有变量中定义的方法
g.__test_class.print_info()
其实官方文档说了这么多,实际意思就是 类和涉及IO的 变量 不能序列化,导致不能在g中作为全局变量,如果要作为全局变量,需要 用2个前下划线__ 命名,比如 g.__db = Bond()
 
class Bond:
    pass
 
不然就会报错:

_pickle.PickingError: Can't pick <class 'IOEngine.user_module : attribute loopup






 
 

欢迎关注公众号 查看全部
关于持久化

为什么要做持久化处理

服务器异常、策略优化等诸多场景,都会使得正在进行的模拟盘和实盘策略存在中断后再重启的需求,但是一旦交易中止后,策略中存储在内存中的全局变量就清空了,因此通过持久化处理为量化交易保驾护航必不可少。

量化框架持久化处理

使用pickle模块保存股票池、账户信息、订单信息、全局变量g定义的变量等内容。

注意事项:

框架会在before_trading_start(隔日开始)、handle_data、after_trading_end事件后触发持久化信息更新及保存操作;

券商升级/环境重启后恢复交易时,框架会先执行策略initialize函数再执行持久化信息恢复操作。
 
如果持久化信息保存有策略定义的全局对象g中的变量,将会以持久化信息中的变量覆盖掉initialize函数中初始化的该变量。

1 全局变量g中不能被序列化的变量将不会被保存。
您可在initialize中初始化该变量时名字以'__'开头;

2 涉及到IO(打开的文件,实例化的类对象等)的对象是不能被序列化的;

3 全局变量g中以'__'开头的变量为私有变量,持久化时将不会被保存;
 
示例代码:
class Test(object):
count = 5

def print_info(self):
self.count += 1
log.info("a" * self.count)


def initialize(context):
g.security = "600570.SS"
set_universe(g.security)
# 初始化无法被序列化类对象,并赋值为私有变量,落地持久化信息时跳过保存该变量
g.__test_class = Test()

def handle_data(context, data):
# 调用私有变量中定义的方法
g.__test_class.print_info()

其实官方文档说了这么多,实际意思就是 类和涉及IO的 变量 不能序列化,导致不能在g中作为全局变量,如果要作为全局变量,需要 用2个前下划线__ 命名,比如 g.__db = Bond()
 
class Bond:
    pass
 
不然就会报错:


_pickle.PickingError: Can't pick <class 'IOEngine.user_module : attribute loopup



mmexport1661160949191.jpg

 
 

欢迎关注公众号

虚拟机 云服务器 运行qmt 方案

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 319 次浏览 • 2022-08-20 17:17 • 来自相关话题

点击查看大图

众所周知,部分券商(国盛证券)限制了虚拟机登录QMT。 
 
比如在vmare中安装了QMT,可以在QMT的信息里面看到:





点击查看大图

 
比如上面的截图, 如果和实体机的设备信息做一个对比,可以看到,虚拟机下的QMT的硬盘序列号(红框的位置) 是空的,而实体物理机下,红框的硬盘序列号 是有内容的。 所以一个办法是尝试修改这个硬盘序列号。
 
或者换一个支持虚拟机的券商。其实这个限制是券商端定制的功能,部分券商并没有限制虚拟机禁止登陆QMT的。
 
比如国金证券的QMT,可以在虚拟机或者云服务器上登录。费率也可以万一免五,参考文章:
http://www.30daydo.com/article/44479 查看全部
20220820001.png

点击查看大图

众所周知,部分券商(国盛证券)限制了虚拟机登录QMT。 
 
比如在vmare中安装了QMT,可以在QMT的信息里面看到:

20220820002.png

点击查看大图

 
比如上面的截图, 如果和实体机的设备信息做一个对比,可以看到,虚拟机下的QMT的硬盘序列号(红框的位置) 是空的,而实体物理机下,红框的硬盘序列号 是有内容的。 所以一个办法是尝试修改这个硬盘序列号。
 
或者换一个支持虚拟机的券商。其实这个限制是券商端定制的功能,部分券商并没有限制虚拟机禁止登陆QMT的。
 
比如国金证券的QMT,可以在虚拟机或者云服务器上登录。费率也可以万一免五,参考文章:
http://www.30daydo.com/article/44479

通过mini qmt xtdata获取tick数据 python代码

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 356 次浏览 • 2022-08-17 18:03 • 来自相关话题

 def get_tick(code, start_time, end_time, period='tick'):
from xtquant import xtdata

xtdata.download_history_data(code, period=period, start_time=start_time, end_time=end_time)
data = xtdata.get_local_data(field_list=, stock_code=, period=period, count=10)
result_list = data df = pd.DataFrame(result_list)

df['time_str'] = df['time'].apply(lambda x: datetime.datetime.fromtimestamp(x / 1000.0))
return df
上面python代码传入一个代码,和初试时间,需要的周期数据(分钟,秒,日等),就可以返回一个dataframe格式的数据了。
 

欢迎关注公众号 查看全部
 
def get_tick(code, start_time, end_time, period='tick'):
from xtquant import xtdata

xtdata.download_history_data(code, period=period, start_time=start_time, end_time=end_time)
data = xtdata.get_local_data(field_list=, stock_code=
, period=period, count=10)
result_list = data
    df = pd.DataFrame(result_list)

df['time_str'] = df['time'].apply(lambda x: datetime.datetime.fromtimestamp(x / 1000.0))
return df

上面python代码传入一个代码,和初试时间,需要的周期数据(分钟,秒,日等),就可以返回一个dataframe格式的数据了。
 

欢迎关注公众号

Ptrade下单接口 order,order_target, order_value,order_target_value的区别

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 275 次浏览 • 2022-08-11 23:57 • 来自相关话题

order_target 接口通过持仓数量比较将入参的目标数量转换成需要交易的成交,传入 order
接口

order_value 接口通过 金额/限价 或者 金额/默认最新价 两种方式转换成需要交易的数量,
传入 order 接口

order_target_value 接口通过持仓金额比较得到需要交易的金额, 金额/限价 或者 金额/默
认最新价 两种方式转换成需要交易的数量,传入 order 接口




所以其他几个接口都是对order的封装。
 
order接口的逻辑:order 接口:
一、
先判断 limit_price 是否传入,传入则用传入价格限价,不传入则最新价代替,都是
限价方式报单。二、
判断隔夜单和交易时间,交易时间(9:10(系统可配)~15:00)范围的订单会马上
加入未处理订单队列,其他订单先放到一个队列,等时间到交易时间就放到未处理订单
队列三、
未处理订单队列的订单会进行限价判断,如果没有传入限价就按当前最新价处理,
然后报柜台
  

欢迎关注公众号 查看全部
order_target 接口通过持仓数量比较将入参的目标数量转换成需要交易的成交,传入 order
接口

order_value 接口通过 金额/限价 或者 金额/默认最新价 两种方式转换成需要交易的数量,
传入 order 接口

order_target_value 接口通过持仓金额比较得到需要交易的金额, 金额/限价 或者 金额/默
认最新价 两种方式转换成需要交易的数量,传入 order 接口




所以其他几个接口都是对order的封装。
 
order接口的逻辑:
order 接口:
一、
先判断 limit_price 是否传入,传入则用传入价格限价,不传入则最新价代替,都是
限价方式报单。
二、
判断隔夜单和交易时间,交易时间(9:10(系统可配)~15:00)范围的订单会马上
加入未处理订单队列,其他订单先放到一个队列,等时间到交易时间就放到未处理订单
队列
三、
未处理订单队列的订单会进行限价判断,如果没有传入限价就按当前最新价处理,
然后报柜台

  

欢迎关注公众号

去除导流公众号的网站 油猴脚本

网络李魔佛 发表了文章 • 0 个评论 • 258 次浏览 • 2022-08-11 13:26 • 来自相关话题

先安装油猴工具。然后导入下面的油猴脚本
 

去除博客导流公众号
// ==UserScript==
// @name 去除博客导流公众号
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 去除openwrite“博客导流公众号”功能
// @author You
// @include http*://*
// @grant none
// ==/UserScript==

(function() {
'use strict';

destroyBTWPlugin();

function destroyBTWPlugin() {
// 判断是否有插件
const hasBTWPlugin = typeof BTWPlugin == "function"

if (hasBTWPlugin) {
// 获取属性
const plugin = new BTWPlugin().options;
if (plugin) {
// 删除元素
const read_more_wrap = document.getElementById("read-more-wrap")
if (read_more_wrap) {
read_more_wrap.remove();
}
// 删除样式
const ctner = document.getElementById(plugin.id)
if (ctner) {
ctner.removeAttribute("style");
}
}
}
}
})();
 
绕过openwrite公众号导流
// ==UserScript==
// @name 绕过openwrite公众号导流
// @namespace http://tampermonkey.net/
// @version 1.6
// @description 去除openwrite“博客导流公众号”功能
// @author GoodbyeNJN
// @license GPLv3
// @match *://*/*
// @grant none
// ==/UserScript==

/**
* openwrite 脚本基本逻辑:
* 函数名和属性名储存在一个数组中(搜索“阅读全文”可定位到),取值时通过对应的索引取出对应的值。
* 先构造一个对象(搜索“const .* = function”可定位到),在下方不远处给它的 prototype 上添加 options 和 init。
* 点击弹窗中的“提交”按钮时,触发回调(搜索“alert”可定位到),解析后具体代码如下:

* function () {
* const val = $("#btw-modal-input").val();
* if (val === "") {
* alert("请输入校验码!");
* $("#btw-modal-input").focus();
* return;
* }
* const { blogId } = btw.options
* const api = "https://my.openwrite.cn/code/check";
* const url = "" + api + "?blogId=" + blogId + "&code=" + val + "";
* $.get(url, function (res) {
* if (res.result === true) {
* localStorage.setItem("TOKEN_" + blogId + "", blogId);
* $("#btw-modal-wrap, #read-more-wrap").remove();
* $("#" + btw.options.id + "").height("");
* } else {
* alert("校验码有误!");
* }
* });
* }

*/

"use strict";

const READ_MORE_ID = "read-more-wrap";

/**
* 判断是否存在插件
*/
const hasBtwPlugin = () => {
const hasBTWPlugin = typeof BTWPlugin === "function";
const hasJquery = typeof $ === "function";

return hasBTWPlugin && hasJquery;
};

/**
* 判断是否存在“阅读全文”按钮
*/
const hasReadMoreBtn = () => {
return !!document.getElementById(READ_MORE_ID);
};

/**
* 获取插件初始化选项
*/
const getOptions = () => {
return (
BTWPlugin.prototype.options || {
id: "container",
blogId: "",
name: "",
qrcode: "",
keyword: "",
}
);
};

/**
* 监听“阅读全文”按钮的出现
* 用于首次触发该脚本且无按钮时,监听后续的按钮出现事件
*/
const listenReadMoreBtnShow = fn => {
const observer = new MutationObserver(mutations =>
mutations.forEach(mutation =>
mutation.addedNodes.forEach(node => {
if (node.id === READ_MORE_ID) {
observer.disconnect();
fn();
}
}),
),
);

const { id } = getOptions();
const parent = document.getElementById(id);
parent && observer.observe(parent, { childList: true });
};

/**
* 监听部分 history 改动事件
* 用于 spa 页面路由变化时自动展示全文
*/
const listenHistoryChange = fn => {
const wrap = type => {
const fn = history[type];
return function (...args) {
const res = fn.apply(this, args);
const e = new Event(type);
e.arguments = args;
window.dispatchEvent(e);
return res;
};
};

history.pushState = wrap("pushState");
history.replaceState = wrap("replaceState");

window.addEventListener("replaceState", fn);
window.addEventListener("pushState", fn);
window.addEventListener("hashchange", fn);
};

/**
* 展示全文
*/
const showHiddenText = () => {
const { id, blogId } = getOptions();
console.log("id:", id);
localStorage.setItem(`TOKEN_${blogId}`, blogId);
$(`#${READ_MORE_ID}`).remove();
$(`#${id}`).height("");
};

(function () {
if (!hasBtwPlugin()) {
return;
}

$().ready(() => {
listenHistoryChange(showHiddenText);

if (hasReadMoreBtn()) {
showHiddenText();
} else {
listenReadMoreBtnShow(showHiddenText);
}
});
})(); 查看全部
先安装油猴工具。然后导入下面的油猴脚本
 

去除博客导流公众号
// ==UserScript==
// @name 去除博客导流公众号
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 去除openwrite“博客导流公众号”功能
// @author You
// @include http*://*
// @grant none
// ==/UserScript==

(function() {
'use strict';

destroyBTWPlugin();

function destroyBTWPlugin() {
// 判断是否有插件
const hasBTWPlugin = typeof BTWPlugin == "function"

if (hasBTWPlugin) {
// 获取属性
const plugin = new BTWPlugin().options;
if (plugin) {
// 删除元素
const read_more_wrap = document.getElementById("read-more-wrap")
if (read_more_wrap) {
read_more_wrap.remove();
}
// 删除样式
const ctner = document.getElementById(plugin.id)
if (ctner) {
ctner.removeAttribute("style");
}
}
}
}
})();

 
绕过openwrite公众号导流
// ==UserScript==
// @name 绕过openwrite公众号导流
// @namespace http://tampermonkey.net/
// @version 1.6
// @description 去除openwrite“博客导流公众号”功能
// @author GoodbyeNJN
// @license GPLv3
// @match *://*/*
// @grant none
// ==/UserScript==

/**
* openwrite 脚本基本逻辑:
* 函数名和属性名储存在一个数组中(搜索“阅读全文”可定位到),取值时通过对应的索引取出对应的值。
* 先构造一个对象(搜索“const .* = function”可定位到),在下方不远处给它的 prototype 上添加 options 和 init。
* 点击弹窗中的“提交”按钮时,触发回调(搜索“alert”可定位到),解析后具体代码如下:

* function () {
* const val = $("#btw-modal-input").val();
* if (val === "") {
* alert("请输入校验码!");
* $("#btw-modal-input").focus();
* return;
* }
* const { blogId } = btw.options
* const api = "https://my.openwrite.cn/code/check";
* const url = "" + api + "?blogId=" + blogId + "&code=" + val + "";
* $.get(url, function (res) {
* if (res.result === true) {
* localStorage.setItem("TOKEN_" + blogId + "", blogId);
* $("#btw-modal-wrap, #read-more-wrap").remove();
* $("#" + btw.options.id + "").height("");
* } else {
* alert("校验码有误!");
* }
* });
* }

*/

"use strict";

const READ_MORE_ID = "read-more-wrap";

/**
* 判断是否存在插件
*/
const hasBtwPlugin = () => {
const hasBTWPlugin = typeof BTWPlugin === "function";
const hasJquery = typeof $ === "function";

return hasBTWPlugin && hasJquery;
};

/**
* 判断是否存在“阅读全文”按钮
*/
const hasReadMoreBtn = () => {
return !!document.getElementById(READ_MORE_ID);
};

/**
* 获取插件初始化选项
*/
const getOptions = () => {
return (
BTWPlugin.prototype.options || {
id: "container",
blogId: "",
name: "",
qrcode: "",
keyword: "",
}
);
};

/**
* 监听“阅读全文”按钮的出现
* 用于首次触发该脚本且无按钮时,监听后续的按钮出现事件
*/
const listenReadMoreBtnShow = fn => {
const observer = new MutationObserver(mutations =>
mutations.forEach(mutation =>
mutation.addedNodes.forEach(node => {
if (node.id === READ_MORE_ID) {
observer.disconnect();
fn();
}
}),
),
);

const { id } = getOptions();
const parent = document.getElementById(id);
parent && observer.observe(parent, { childList: true });
};

/**
* 监听部分 history 改动事件
* 用于 spa 页面路由变化时自动展示全文
*/
const listenHistoryChange = fn => {
const wrap = type => {
const fn = history[type];
return function (...args) {
const res = fn.apply(this, args);
const e = new Event(type);
e.arguments = args;
window.dispatchEvent(e);
return res;
};
};

history.pushState = wrap("pushState");
history.replaceState = wrap("replaceState");

window.addEventListener("replaceState", fn);
window.addEventListener("pushState", fn);
window.addEventListener("hashchange", fn);
};

/**
* 展示全文
*/
const showHiddenText = () => {
const { id, blogId } = getOptions();
console.log("id:", id);
localStorage.setItem(`TOKEN_${blogId}`, blogId);
$(`#${READ_MORE_ID}`).remove();
$(`#${id}`).height("");
};

(function () {
if (!hasBtwPlugin()) {
return;
}

$().ready(() => {
listenHistoryChange(showHiddenText);

if (hasReadMoreBtn()) {
showHiddenText();
} else {
listenReadMoreBtnShow(showHiddenText);
}
});
})();

Ptrade抢新上市的可转债

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 257 次浏览 • 2022-08-11 10:20 • 来自相关话题

更新:早上的单子如期挂上了。只是成交量太少,轮不动我的。不过也好,省点心,不用每次盯盘操作。





 
PS: 也不是每一只都是去抢,还是需要提前判断下。规模小的优先。
 

欢迎关注公众号 查看全部
更新:早上的单子如期挂上了。只是成交量太少,轮不动我的。不过也好,省点心,不用每次盯盘操作。

20220811002.png

 
PS: 也不是每一只都是去抢,还是需要提前判断下。规模小的优先。
 

欢迎关注公众号

自己写的包在 PTrade 里如何使用的方法有吗?

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 279 次浏览 • 2022-08-08 03:28 • 来自相关话题

自己写的包在 PTrade 里如何使用的方法有吗?
A:和常规 Python 函数调用时一样的,只是需要和你的其它函数放在同一个脚本
中,暂时不支持跨越脚本文件的调用。
 
所以你写的包,都要放着ptrade的策略里面,不能另外保存到一个地方,然后通过 from xxxx import xxxx 这种方式导入。
 
所以有时候你的ptrade文件会臃肿无比。经常复制粘贴。也是无奈之举。
 

欢迎关注公众号 查看全部
自己写的包在 PTrade 里如何使用的方法有吗?
A:和常规 Python 函数调用时一样的,只是需要和你的其它函数放在同一个脚本
中,暂时不支持跨越脚本文件的调用。
 
所以你写的包,都要放着ptrade的策略里面,不能另外保存到一个地方,然后通过 from xxxx import xxxx 这种方式导入。
 
所以有时候你的ptrade文件会臃肿无比。经常复制粘贴。也是无奈之举。
 

欢迎关注公众号

ptrade支持文件的读写吗,Excel 文件可以读写吗

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 245 次浏览 • 2022-08-08 00:01 • 来自相关话题

 
当前支持 csv,xlsx,txt,pkl 等文件的读取,需要手动将对应文件上传到研究环境中,
然后在回测中使用 get_research_path()+”文件名”获取文件路径后进行读取(见下图),
回写文件类似,可使用 pd.to_csv()等函数存储在研究环境指定目录下。
值得注意的是,当前支持单个文件最大为 50M
 





 
模型每天都会更新的,权重文件,能上传吗?
 
可以,注意文件大小的限制。
 

欢迎关注公众号 查看全部
 
当前支持 csv,xlsx,txt,pkl 等文件的读取,需要手动将对应文件上传到研究环境中,
然后在回测中使用 get_research_path()+”文件名”获取文件路径后进行读取(见下图),
回写文件类似,可使用 pd.to_csv()等函数存储在研究环境指定目录下。
值得注意的是,当前支持单个文件最大为 50M
 

img1.png

 
模型每天都会更新的,权重文件,能上传吗?
 
可以,注意文件大小的限制。
 

欢迎关注公众号

优矿使用的python版本

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 249 次浏览 • 2022-08-07 08:22 • 来自相关话题

应该是变种的python2.7
从底层来看它的报错信息:





 
它是使用python2.7
 
可是异常操作,却可以使用python3的语法
try:
....
except Exception as e:
.....
 
所以有些地方还是得要注意一下 py2和py3的区别
比如py2的字典默认顺序是无序的。(这个有一次调试一个bug耗费了一两个小时,结果发现用了字典,取key,结果发现key的顺序全部是乱的,py3从3.6开始字典的key是有序的)
 
  查看全部
应该是变种的python2.7
从底层来看它的报错信息:

20220807001.png

 
它是使用python2.7
 
可是异常操作,却可以使用python3的语法
try:
....
except Exception as e:
.....
 
所以有些地方还是得要注意一下 py2和py3的区别
比如py2的字典默认顺序是无序的。(这个有一次调试一个bug耗费了一两个小时,结果发现用了字典,取key,结果发现key的顺序全部是乱的,py3从3.6开始字典的key是有序的)
 
 

可转债多因子回测 优矿代码

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 334 次浏览 • 2022-08-06 18:00 • 来自相关话题

可转债里面可用因子很多,一般人最常用的就是溢价率,双低,价格等。
实际运用里面,可以加入很多很多因子,比如正股涨跌幅,正股波动率,转债到期时间,正股ROE等等多大几十个因子。





 
之前写了一个多因子回测的优矿python代码,用户可以自己修改参数,
 
比如下面的正股波动率因子,Bond_Volatility_ENABLE = True
Bond_Volatility_DAYS = 30
TOP_RIPPLE = 50
Bond_Volatility_LOG_ENABLE = True # 波动率日志开关

Bond_Volatility_ENABLE = True 设为True,就是回测过程加入这个因子,设为False就忽略这个因子。
下面的 
Bond_Volatility_DAYS 为N天内的正股波动率,一般设置30天,20天内就够了,因为一年之前的即使波动很大,那对当前转债的影响也很小。
 
TOP_RIPPLE 选择波动率最大的前面N只转债
举个例子,下面转债是根据其对应正股的30天里的波动率选出来的。(当前是8月5日,也就是7月5日到8月5日之间的数据)。





计算波动率具体代码如下;





 
每个因子写成一个类。
 
这样可以不用修改主代码,就可以无限地添加,修改因子。# 基类
class ConditionFilter:

def filters(self, *args, **kwargs):
if self.enable:
return self.fun(*args, **kwargs)
else:
return True

def fun(self, *args, **kwargs):
# 继承的实现这个函数
raise NotImplemented





 
上面是部分过滤因子,也就是不满足的都会被移除。 比如规模大于10亿的会移除。
 
然后得到的结果,进行因子评分。 # 权重 溢价率、转债价格、正股N天涨幅,正股ROE
weights = {'溢价率': 0, '转债价格': 1, '正股N天涨幅': 0, '正股ROE': 0, '规模': 0}
每个权重赋予一个权重分最高是1,最低是0,如果你想回测 低溢价率 策略,只需要把其他因子的权重全部设置为0,溢价率设置为1即可。双底的话就是 溢价率和价格各为0.5 就可以了。
 
设置好参数后,设置你要回测的时间,持仓周期,持有个数等可调参数。
 
稍等片刻就会有结果了。因子越多,运行时间会增加。一般几分钟就可以得到几年来的回测结果。
 





中途可以查看日志
 
完整代码以及运行流程可到知识星球咨询了解。





 

欢迎关注公众号 查看全部
可转债里面可用因子很多,一般人最常用的就是溢价率,双低,价格等。
实际运用里面,可以加入很多很多因子,比如正股涨跌幅,正股波动率,转债到期时间,正股ROE等等多大几十个因子。

20220806001.png

 
之前写了一个多因子回测的优矿python代码,用户可以自己修改参数,
 
比如下面的正股波动率因子,
Bond_Volatility_ENABLE = True
Bond_Volatility_DAYS = 30
TOP_RIPPLE = 50
Bond_Volatility_LOG_ENABLE = True # 波动率日志开关


Bond_Volatility_ENABLE = True 设为True,就是回测过程加入这个因子,设为False就忽略这个因子。
下面的 
Bond_Volatility_DAYS 为N天内的正股波动率,一般设置30天,20天内就够了,因为一年之前的即使波动很大,那对当前转债的影响也很小。
 
TOP_RIPPLE 选择波动率最大的前面N只转债
举个例子,下面转债是根据其对应正股的30天里的波动率选出来的。(当前是8月5日,也就是7月5日到8月5日之间的数据)。

20220806003.png

计算波动率具体代码如下;

20220806004.png

 
每个因子写成一个类。
 
这样可以不用修改主代码,就可以无限地添加,修改因子。
# 基类
class ConditionFilter:

def filters(self, *args, **kwargs):
if self.enable:
return self.fun(*args, **kwargs)
else:
return True

def fun(self, *args, **kwargs):
# 继承的实现这个函数
raise NotImplemented


20220806005.png

 
上面是部分过滤因子,也就是不满足的都会被移除。 比如规模大于10亿的会移除。
 
然后得到的结果,进行因子评分。 
# 权重 溢价率、转债价格、正股N天涨幅,正股ROE
weights = {'溢价率': 0, '转债价格': 1, '正股N天涨幅': 0, '正股ROE': 0, '规模': 0}

每个权重赋予一个权重分最高是1,最低是0,如果你想回测 低溢价率 策略,只需要把其他因子的权重全部设置为0,溢价率设置为1即可。双底的话就是 溢价率和价格各为0.5 就可以了。
 
设置好参数后,设置你要回测的时间,持仓周期,持有个数等可调参数。
 
稍等片刻就会有结果了。因子越多,运行时间会增加。一般几分钟就可以得到几年来的回测结果。
 

20220806006.png

中途可以查看日志
 
完整代码以及运行流程可到知识星球咨询了解。

ZSXQ_20220806_180545705.png

 

欢迎关注公众号

ptrade策略代码:集合竞价追涨停策略

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 369 次浏览 • 2022-08-04 15:24 • 来自相关话题

这个是示例代码,我们来大体讲解一下:def initialize(context):
# 初始化此策略
# 设置我们要操作的股票池, 这里我们只操作一支股票
g.security = '600570.SS'
set_universe(g.security)
#每天9:23分运行集合竞价处理函数
run_daily(context, aggregate_auction_func, time='9:23')

def aggregate_auction_func(context):
stock = g.security
#最新价
snapshot = get_snapshot(stock)
price = snapshot[stock]['last_px']
#涨停价
up_limit = snapshot[stock]['up_px']
#如果最新价不小于涨停价,买入
if float(price) >= float(up_limit):
order(g.security, 100, limit_price=up_limit)

def handle_data(context, data):
pass
 
分解讲解:def initialize(context):
# 初始化此策略
# 设置我们要操作的股票池, 这里我们只操作一支股票
g.security = '600570.SS'
set_universe(g.security)
#每天9:23分运行集合竞价处理函数
run_daily(context, aggregate_auction_func, time='9:23')
initialize是初始化函数,一定要有的函数。在策略运行时首先运行的,而且只会运行一次。
set_universe(g.security) 在把标的代码放进去。这里是  '600570.SS' 记得要有后缀,上证股票用 .SS ,深圳股票用.SZ。
 
run_daily(context, aggregate_auction_func, time='9:23')
这一行是设定每天运行一次。这个策略是日线级别的,所以每天只要运行一次就可以了。 分别传入3个参数。

第一个参数固定是context,第二个要执行的函数名,记住只能传函数名,不能把括号也加进去,第三个参数,是运行的时间,现在设定在 9:23
 
那么接下来就是要实现上面那个函数名了: aggregate_auction_func,这个名字可以随意定义def aggregate_auction_func(context):
stock = g.security
#最新价
snapshot = get_snapshot(stock)
price = snapshot[stock]['last_px']
#涨停价
up_limit = snapshot[stock]['up_px']
#如果最新价不小于涨停价,买入
if float(price) >= float(up_limit):
order(g.security, 100, limit_price=up_limit)
stock = g.security , g是全局变量,用来在上下文中传递数据。这里就是上面的'600570.SS'
 
snapshot = get_snapshot(stock)
这个就是获取行情数据,当前的价格
 

up_limit = snapshot[stock]['up_px']
拿到这个标的的涨停价

if float(price) >= float(up_limit):
这个是当前价格大于涨停板价格(主要考虑了四舍五入,用于大号比较安全)
 
order(g.security, 100, limit_price=up_limit)
这个就是下单函数。
买入100股,不限价,市价成交。
 
然后就可以点击运行交易。 
 
程序每天都会自动交易。



欢迎关注公众号
 
 

  查看全部
这个是示例代码,我们来大体讲解一下:
def initialize(context):
# 初始化此策略
# 设置我们要操作的股票池, 这里我们只操作一支股票
g.security = '600570.SS'
set_universe(g.security)
#每天9:23分运行集合竞价处理函数
run_daily(context, aggregate_auction_func, time='9:23')

def aggregate_auction_func(context):
stock = g.security
#最新价
snapshot = get_snapshot(stock)
price = snapshot[stock]['last_px']
#涨停价
up_limit = snapshot[stock]['up_px']
#如果最新价不小于涨停价,买入
if float(price) >= float(up_limit):
order(g.security, 100, limit_price=up_limit)

def handle_data(context, data):
pass

 
分解讲解:
def initialize(context):
# 初始化此策略
# 设置我们要操作的股票池, 这里我们只操作一支股票
g.security = '600570.SS'
set_universe(g.security)
#每天9:23分运行集合竞价处理函数
run_daily(context, aggregate_auction_func, time='9:23')

initialize是初始化函数,一定要有的函数。在策略运行时首先运行的,而且只会运行一次。
set_universe(g.security) 在把标的代码放进去。这里是  '600570.SS' 记得要有后缀,上证股票用 .SS ,深圳股票用.SZ。
 
run_daily(context, aggregate_auction_func, time='9:23')
这一行是设定每天运行一次。这个策略是日线级别的,所以每天只要运行一次就可以了。 分别传入3个参数。

第一个参数固定是context,第二个要执行的函数名,记住只能传函数名,不能把括号也加进去,第三个参数,是运行的时间,现在设定在 9:23
 
那么接下来就是要实现上面那个函数名了: aggregate_auction_func,这个名字可以随意定义
def aggregate_auction_func(context):
stock = g.security
#最新价
snapshot = get_snapshot(stock)
price = snapshot[stock]['last_px']
#涨停价
up_limit = snapshot[stock]['up_px']
#如果最新价不小于涨停价,买入
if float(price) >= float(up_limit):
order(g.security, 100, limit_price=up_limit)

stock = g.security , g是全局变量,用来在上下文中传递数据。这里就是上面的'600570.SS'
 
snapshot = get_snapshot(stock)
这个就是获取行情数据,当前的价格
 

up_limit = snapshot[stock]['up_px']
拿到这个标的的涨停价

if float(price) >= float(up_limit):
这个是当前价格大于涨停板价格(主要考虑了四舍五入,用于大号比较安全)
 
order(g.security, 100, limit_price=up_limit)
这个就是下单函数。
买入100股,不限价,市价成交。
 
然后就可以点击运行交易。 
 
程序每天都会自动交易。



欢迎关注公众号