qmt position对象里面有哪些属性?

QMT李魔佛 发表了文章 • 0 个评论 • 1086 次浏览 • 2023-02-27 22:12 • 来自相关话题

查看属性的代码:
  obj_list = get_trade_detail_data(ACCOUNT,'stock','position')
for obj in obj_list:
print(obj.m_strInstrumentID,obj.m_strInstrumentName,'----')
# 查看有哪些属性字段
print('='*10)
for item in dir(obj):
if not item.startswith('__'):
print(item)

print('='*10)
得到的position的内置属性有下面的:m_bIsToday
m_dAvgOpenPrice
m_dCloseAmount
m_dCloseProfit
m_dFloatProfit
m_dInstrumentValue
m_dLastPrice
m_dLastSettlementPrice
m_dMargin
m_dMarketValue
m_dOpenCost
m_dOpenPrice
m_dPositionCost
m_dPositionProfit
m_dProfitRate
m_dRealUsedMargin
m_dRedemptionVolume
m_dReferenceRate
m_dRoyalty
m_dSettlementPrice
m_dSingleCost
m_dStaticHoldMargin
m_dStockLastPrice
m_dStructFundVol
m_dTotalCost
m_eFutureTradeType
m_eSideFlag
m_nCanUseVolume
m_nCidIncrease
m_nCidIsDelist
m_nCidRateOfCurrentLine
m_nCidRateOfTotalValue
m_nCloseVolume
m_nCoveredVolume
m_nDirection
m_nEnableExerciseVolume
m_nFrozenVolume
m_nHedgeFlag
m_nLegId
m_nOnRoadVolume
m_nOptCombUsedVolume
m_nPREnableVolume
m_nVolume
m_nYesterdayVolume
m_strAccountID
m_strAccountKey
m_strComTradeID
m_strExchangeID
m_strExchangeName
m_strExpireDate
m_strInstrumentID
m_strInstrumentName
m_strOpenDate
m_strProductID
m_strProductName
m_strStockHolder
m_strTradeID
m_strTradingDay
m_xtTag
虽然有上面的属性,但是实际上很可能是空的,并没有值。






  查看全部
查看属性的代码:
 
    obj_list = get_trade_detail_data(ACCOUNT,'stock','position')
for obj in obj_list:
print(obj.m_strInstrumentID,obj.m_strInstrumentName,'----')
# 查看有哪些属性字段
print('='*10)
for item in dir(obj):
if not item.startswith('__'):
print(item)

print('='*10)

得到的position的内置属性有下面的:
m_bIsToday
m_dAvgOpenPrice
m_dCloseAmount
m_dCloseProfit
m_dFloatProfit
m_dInstrumentValue
m_dLastPrice
m_dLastSettlementPrice
m_dMargin
m_dMarketValue
m_dOpenCost
m_dOpenPrice
m_dPositionCost
m_dPositionProfit
m_dProfitRate
m_dRealUsedMargin
m_dRedemptionVolume
m_dReferenceRate
m_dRoyalty
m_dSettlementPrice
m_dSingleCost
m_dStaticHoldMargin
m_dStockLastPrice
m_dStructFundVol
m_dTotalCost
m_eFutureTradeType
m_eSideFlag
m_nCanUseVolume
m_nCidIncrease
m_nCidIsDelist
m_nCidRateOfCurrentLine
m_nCidRateOfTotalValue
m_nCloseVolume
m_nCoveredVolume
m_nDirection
m_nEnableExerciseVolume
m_nFrozenVolume
m_nHedgeFlag
m_nLegId
m_nOnRoadVolume
m_nOptCombUsedVolume
m_nPREnableVolume
m_nVolume
m_nYesterdayVolume
m_strAccountID
m_strAccountKey
m_strComTradeID
m_strExchangeID
m_strExchangeName
m_strExpireDate
m_strInstrumentID
m_strInstrumentName
m_strOpenDate
m_strProductID
m_strProductName
m_strStockHolder
m_strTradeID
m_strTradingDay
m_xtTag

虽然有上面的属性,但是实际上很可能是空的,并没有值。

20230227004.jpg


 

qmt 可转债 双低(阈值)轮动 实盘代码

QMT李魔佛 发表了文章 • 0 个评论 • 1725 次浏览 • 2023-02-26 15:18 • 来自相关话题

之前在星球埋的坑,答应群友写个qmt的双低可转债的轮动实盘代码。
用已有的ptrade的代码,然后部分获取行情和交易接口按照qmt的接口文档(http://qmt.ptradeapi.com )重写,就给了一版。(对,很早以前就有一版ptrade的转债双低的了)
 
无论是qmt还是ptrade,都只是一个工具,用熟悉了,都无所哪个好哪个不好。





 





 





 
 
完整代码在个人星球。
 
觉得之前星球太便宜了,不仅给了代码,还部署了接口免费使用,通过接口获取可转债的实时数据,强赎天数,规模,溢价率,评级等等一系列数据。 而且随着时间的推移,里面积累的数据,代码也越来越多,感觉这样对前面进去并不断续费的星友有点公平,尽管以后他们续费都直接打折扣。所以还是按照一些大v运营的意见,逐年涨价策略。
越往后的朋友,因为前面积累的内容越多,因此价格也随之增长。
 
当然有能力可以自己写接口,部署,实盘,获取三方数据的大v,就没必要加了。
  查看全部
之前在星球埋的坑,答应群友写个qmt的双低可转债的轮动实盘代码。
用已有的ptrade的代码,然后部分获取行情和交易接口按照qmt的接口文档(http://qmt.ptradeapi.com )重写,就给了一版。(对,很早以前就有一版ptrade的转债双低的了)
 
无论是qmt还是ptrade,都只是一个工具,用熟悉了,都无所哪个好哪个不好。

20230217003.jpg

 

20230226011.jpg

 

20230226012.jpg

 
 
完整代码在个人星球。
 
觉得之前星球太便宜了,不仅给了代码,还部署了接口免费使用,通过接口获取可转债的实时数据,强赎天数,规模,溢价率,评级等等一系列数据。 而且随着时间的推移,里面积累的数据,代码也越来越多,感觉这样对前面进去并不断续费的星友有点公平,尽管以后他们续费都直接打折扣。所以还是按照一些大v运营的意见,逐年涨价策略。
越往后的朋友,因为前面积累的内容越多,因此价格也随之增长。
 
当然有能力可以自己写接口,部署,实盘,获取三方数据的大v,就没必要加了。
 

qmt软件里面的快速计算是在什么模式下使用的?

QMT李魔佛 发表了文章 • 0 个评论 • 1044 次浏览 • 2023-02-25 13:35 • 来自相关话题

QMT 平台模型是根据行情驱动,逐 K 线运行的。
 
即点击运行模型时,模型是从第 0 根 K 线开始运行到最后一根 K 线(如想加快模型运行速度,可以策略编辑器 - 基本信息中设置快速计算,限制计算范围,只计算最新的指定数量的 K 线范围),每根 K 线调用一次 Python 模型中的 handlebar(ContextInfo) 函数。
 
也就是你点击“运行”按钮的时候,如果你的快速计算默认设置的是0,
 
handlebar里面的k线是从2005年1月1日运行的,即使你在代码里面设置了运行时间:
def init(ContextInfo):
print("==============start==========")
ContextInfo.start = '2023-02-20 10:00:00'
ContextInfo.end = '2023-02-23 10:00:00'或者在回测参数里面设置的时间:






都是不管用的。
 
需要在代码里添加一句:
if not ContextInfo.is_last_bar():
return 
 
或者 把快速计算的值设置为1, 就只会以最新的k线计算。也就是只会执行1次handlebar。





 
不得不说,qmt的说明文档很让人困惑的。笔者也多次吐槽了。
如果没有编程的朋友,不建议自己折腾了。不少编程大咖都惊呼这软件和文档入门太难,文档太扯淡。
如果需要qmt策略代码 和实盘代码 代写,可以在公众号后台留言:qmt代写
 
 
  查看全部
QMT 平台模型是根据行情驱动,逐 K 线运行的。
 
即点击运行模型时,模型是从第 0 根 K 线开始运行到最后一根 K 线(如想加快模型运行速度,可以策略编辑器 - 基本信息中设置快速计算,限制计算范围,只计算最新的指定数量的 K 线范围),每根 K 线调用一次 Python 模型中的 handlebar(ContextInfo) 函数。
 
也就是你点击“运行”按钮的时候,如果你的快速计算默认设置的是0,
 
handlebar里面的k线是从2005年1月1日运行的,即使你在代码里面设置了运行时间:
def init(ContextInfo):
print("==============start==========")
ContextInfo.start = '2023-02-20 10:00:00'
ContextInfo.end = '2023-02-23 10:00:00'
或者在回测参数里面设置的时间:

20230225001.jpg


都是不管用的。
 
需要在代码里添加一句:
    if not ContextInfo.is_last_bar():
return
 
 
或者 把快速计算的值设置为1, 就只会以最新的k线计算。也就是只会执行1次handlebar。

20230225002.jpg

 
不得不说,qmt的说明文档很让人困惑的。笔者也多次吐槽了。
如果没有编程的朋友,不建议自己折腾了。不少编程大咖都惊呼这软件和文档入门太难,文档太扯淡。
如果需要qmt策略代码 和实盘代码 代写,可以在公众号后台留言:qmt代写
 
 
 

qmt隔夜文件单(python代码实现)实盘代码

QMT李魔佛 发表了文章 • 0 个评论 • 1462 次浏览 • 2023-02-24 14:17 • 来自相关话题

 代码基于iquant平台编写。可以拿去参考参考。# encoding:gbk
import logging
import pandas as pd
from datetime import datetime, timedelta, time
from decimal import InvalidOperation
from decimal import Decimal as D
from READFILE import read_file

logging.basicConfig(level=logging.INFO)
# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 规避 account_callback 的 Racing Condition
RUN_TIME_DELAY = 10

# global FILEPATH, DIR, PRICE, VOL, START_TIME, account
SH_pattern = r'^[1-9]\d{5}\.(sh|SH)$'
SZ_pattern = r'^(?!39)\d{6}\.(sz|SZ)$'
SH_prefix = ['5', '6', '9', '11']
SZ_prefix = ['0', '2', '30', '12', '159']
COLNAMES = ['direction', 'vol', 'price', 'start_time']


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)

ContextInfo.can_order = False
ContextInfo.all_order_done = False

if not load_file_order(ContextInfo):
load_sys_order(ContextInfo)

# load_file_order(ContextInfo)
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
(datetime.now() + timedelta(seconds=RUN_TIME_DELAY)).strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True


def handlebar(ContextInfo):
return


def load_file_order(ContextInfo):
def _price_vol_filtering(row):
if not isinstance(row.start_time, time):
logging.warning('读取{0}指令时间失败: {1}'.format(row.name, row.start_time))
return None
if row.direction not in ['买', '卖']:
logging.warning('读取{0}买卖方向失败: {1}'.format(row.name, row.direction))
return None
try:
# parse start_time
curr_start_time = datetime.now().strftime('%Y-%m-%d ') + row.start_time.strftime('%H:%M:%S')
curr_start_time = datetime.strptime(curr_start_time, '%Y-%m-%d %H:%M:%S')
# parse direction
curr_direction = 23 if row.direction == '买' else 24
# parse price and vol
price = D(row.price)
vol = int(row.vol)
return pd.Series([curr_direction, vol, price, curr_start_time])
except InvalidOperation:
logging.warning("读取 {0} 指令价格失败: {1}".format(row.name, row.price))
return None
except ValueError:
logging.warning('读取 {0} 下单总量失败: {1}'.format(row.name, row.vol))
return None

def _name_parser(asset_name):
# 目前默认用户输入.SH 或.SZ时标的名称正确
if '.SH' in asset_name or '.SZ' in asset_name:
# todo: SH/SZ_pattern regex check here?
return asset_name
else:
raise ValueError('{0} 标的代码不合法'.format(asset_name))

try:
tmp_df = read_file(FILEPATH, names=COLNAMES, index_col=0)
except:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None

tmp_df.index = tmp_df.index.to_series().astype(str)
tmp_df.index = tmp_df.index.str.strip()
tmp_df.index = tmp_df.index.str.upper()
tmp_df.index = tmp_df.index.to_series().apply(_name_parser).dropna()
tmp_df = tmp_df.apply(_price_vol_filtering, axis=1, broadcast=True).dropna()
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return False

tmp_df.set_axis(COLNAMES, axis='columns', inplace=True)
# 挂单成功Flag
tmp_df['finished'] = [False] * tmp_df.shape[0]
ContextInfo.order_df = tmp_df
ContextInfo.set_universe(ContextInfo.order_df.index.tolist())
return True


def load_sys_order(ContextInfo):
try:
asset_name = ContextInfo.stockcode + '.' + ContextInfo.market
ContextInfo.set_universe([asset_name])
direction = 23 if DIR == '买入' else 24
start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
price = D(PRICE)
vol = int(VOL)
except BaseException:
raise ValueError("读取策略面板交易配置失败。请尝试修正挂单配置文件或者策略面板参数。")

price = float(price)
ContextInfo.order_df = pd.DataFrame(data=[direction, vol, price, start_time], index=COLNAMES,
columns=[asset_name]).T
ContextInfo.order_df['finished'] = False
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.all_order_done:
return
for curr_asset in ContextInfo.get_universe():
if not ContextInfo.order_df.loc[curr_asset].finished \
and datetime.now() > ContextInfo.order_df.loc[curr_asset].start_time:
curr_order = ContextInfo.order_df.loc[curr_asset]
direction = int(curr_order.direction)
txt_direction = '买入' if direction == 23 else '卖出'
price = float(D(curr_order.price))
vol = int(curr_order.vol)
order_remark = '隔日文件挂单: 以 {0} {1} {2}'.format(price, txt_direction, curr_asset)
passorder(direction, 1101, ContextInfo.accID, curr_asset, 11, price, vol, order_remark, 1, order_remark,
ContextInfo)
ContextInfo.order_df.loc[curr_asset, 'finished'] = True

ContextInfo.all_order_done = all(ContextInfo.order_df['finished'].tolist())


def order_callback(ContextInfo, orderInfo):
curr_asset = orderInfo.m_strInstrumentID + '.' + orderInfo.m_strExchangeID
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus
if '隔日文件挂单' in curr_remark and curr_status == 57:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:报单废单 (柜台返回失败),原因:{1} 尝试重报'.format(curr_asset, orderInfo.m_strCancelInfo))
elif '隔日文件挂单' in curr_remark and curr_status == 50:
logging.info('{0} 隔日文件挂单:报单成功'.format(curr_asset))
return


def orderError_callback(ContextInfo, orderArgs, errMsg):
curr_asset = orderArgs.orderCode
if '隔日文件挂单' in orderArgs.strategyName:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:账号下单异常 (COS/iQuant校验失败), 错误消息:{1} 尝试重报'.format(curr_asset, errMsg))
return






 把上述代码复制到iquant里面,然后部署到策略运行,运行策略,切换为实盘 查看全部
20230224003.jpg

 代码基于iquant平台编写。可以拿去参考参考。
# encoding:gbk
import logging
import pandas as pd
from datetime import datetime, timedelta, time
from decimal import InvalidOperation
from decimal import Decimal as D
from READFILE import read_file

logging.basicConfig(level=logging.INFO)
# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 规避 account_callback 的 Racing Condition
RUN_TIME_DELAY = 10

# global FILEPATH, DIR, PRICE, VOL, START_TIME, account
SH_pattern = r'^[1-9]\d{5}\.(sh|SH)$'
SZ_pattern = r'^(?!39)\d{6}\.(sz|SZ)$'
SH_prefix = ['5', '6', '9', '11']
SZ_prefix = ['0', '2', '30', '12', '159']
COLNAMES = ['direction', 'vol', 'price', 'start_time']


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)

ContextInfo.can_order = False
ContextInfo.all_order_done = False

if not load_file_order(ContextInfo):
load_sys_order(ContextInfo)

# load_file_order(ContextInfo)
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
(datetime.now() + timedelta(seconds=RUN_TIME_DELAY)).strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True


def handlebar(ContextInfo):
return


def load_file_order(ContextInfo):
def _price_vol_filtering(row):
if not isinstance(row.start_time, time):
logging.warning('读取{0}指令时间失败: {1}'.format(row.name, row.start_time))
return None
if row.direction not in ['买', '卖']:
logging.warning('读取{0}买卖方向失败: {1}'.format(row.name, row.direction))
return None
try:
# parse start_time
curr_start_time = datetime.now().strftime('%Y-%m-%d ') + row.start_time.strftime('%H:%M:%S')
curr_start_time = datetime.strptime(curr_start_time, '%Y-%m-%d %H:%M:%S')
# parse direction
curr_direction = 23 if row.direction == '买' else 24
# parse price and vol
price = D(row.price)
vol = int(row.vol)
return pd.Series([curr_direction, vol, price, curr_start_time])
except InvalidOperation:
logging.warning("读取 {0} 指令价格失败: {1}".format(row.name, row.price))
return None
except ValueError:
logging.warning('读取 {0} 下单总量失败: {1}'.format(row.name, row.vol))
return None

def _name_parser(asset_name):
# 目前默认用户输入.SH 或.SZ时标的名称正确
if '.SH' in asset_name or '.SZ' in asset_name:
# todo: SH/SZ_pattern regex check here?
return asset_name
else:
raise ValueError('{0} 标的代码不合法'.format(asset_name))

try:
tmp_df = read_file(FILEPATH, names=COLNAMES, index_col=0)
except:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None

tmp_df.index = tmp_df.index.to_series().astype(str)
tmp_df.index = tmp_df.index.str.strip()
tmp_df.index = tmp_df.index.str.upper()
tmp_df.index = tmp_df.index.to_series().apply(_name_parser).dropna()
tmp_df = tmp_df.apply(_price_vol_filtering, axis=1, broadcast=True).dropna()
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return False

tmp_df.set_axis(COLNAMES, axis='columns', inplace=True)
# 挂单成功Flag
tmp_df['finished'] = [False] * tmp_df.shape[0]
ContextInfo.order_df = tmp_df
ContextInfo.set_universe(ContextInfo.order_df.index.tolist())
return True


def load_sys_order(ContextInfo):
try:
asset_name = ContextInfo.stockcode + '.' + ContextInfo.market
ContextInfo.set_universe([asset_name])
direction = 23 if DIR == '买入' else 24
start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
price = D(PRICE)
vol = int(VOL)
except BaseException:
raise ValueError("读取策略面板交易配置失败。请尝试修正挂单配置文件或者策略面板参数。")

price = float(price)
ContextInfo.order_df = pd.DataFrame(data=[direction, vol, price, start_time], index=COLNAMES,
columns=[asset_name]).T
ContextInfo.order_df['finished'] = False
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.all_order_done:
return
for curr_asset in ContextInfo.get_universe():
if not ContextInfo.order_df.loc[curr_asset].finished \
and datetime.now() > ContextInfo.order_df.loc[curr_asset].start_time:
curr_order = ContextInfo.order_df.loc[curr_asset]
direction = int(curr_order.direction)
txt_direction = '买入' if direction == 23 else '卖出'
price = float(D(curr_order.price))
vol = int(curr_order.vol)
order_remark = '隔日文件挂单: 以 {0} {1} {2}'.format(price, txt_direction, curr_asset)
passorder(direction, 1101, ContextInfo.accID, curr_asset, 11, price, vol, order_remark, 1, order_remark,
ContextInfo)
ContextInfo.order_df.loc[curr_asset, 'finished'] = True

ContextInfo.all_order_done = all(ContextInfo.order_df['finished'].tolist())


def order_callback(ContextInfo, orderInfo):
curr_asset = orderInfo.m_strInstrumentID + '.' + orderInfo.m_strExchangeID
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus
if '隔日文件挂单' in curr_remark and curr_status == 57:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:报单废单 (柜台返回失败),原因:{1} 尝试重报'.format(curr_asset, orderInfo.m_strCancelInfo))
elif '隔日文件挂单' in curr_remark and curr_status == 50:
logging.info('{0} 隔日文件挂单:报单成功'.format(curr_asset))
return


def orderError_callback(ContextInfo, orderArgs, errMsg):
curr_asset = orderArgs.orderCode
if '隔日文件挂单' in orderArgs.strategyName:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:账号下单异常 (COS/iQuant校验失败), 错误消息:{1} 尝试重报'.format(curr_asset, errMsg))
return






 把上述代码复制到iquant里面,然后部署到策略运行,运行策略,切换为实盘

qmt的文档写的有点稀烂

QMT李魔佛 发表了文章 • 0 个评论 • 1059 次浏览 • 2023-02-21 12:41 • 来自相关话题

在部署QMT 在线文档的时候,还是忍不住吐槽下它的文档。
 这也是当时不用QMT的一个重要原因。
 
不仅仅是文档,而且还有它的函数接口的涉及。
 
比如最常用的交易函数,passorder综合交易下单 passorder()
用法: passorder(opType, orderType, accountid, orderCode, prType, modelprice, volume[, strategyName, quickTrade, userOrderId], ContextInfo)
里面有11个参数,可选参数有2个。 对于一个常用函数来说,这个参数有点多了。
 
而更为令人费解的,是它参数里面额设定值
比如第一个opType,操作类型。
 
里面有59个数字:期货六键:

0:开多

1:平昨多

2:平今多

3:开空

4:平昨空

5:平今空

期货四键:

6:平多,优先平今

7:平多,优先平昨

8:平空,优先平今

9:平空,优先平昨

期货两键:

10:卖出,如有多仓,优先平仓,优先平今,如有余量,再开空

11:卖出,如有多仓,优先平仓,优先平昨,如有余量,再开空

12:买入,如有空仓,优先平仓,优先平今,如有余量,再开多

13:买入,如有空仓,优先平仓,优先平昨,如有余量,再开多

14:买入,不优先平仓

15:卖出,不优先平仓

股票买卖:

23:股票买入,或沪港通、深港通股票买入

24:股票卖出,或沪港通、深港通股票卖出

融资融券:

27:融资买入

28:融券卖出

29:买券还券

30:直接还券

31:卖券还款

32:直接还款

33:信用账号股票买入

34:信用账号股票卖出

组合交易:

25:组合买入,或沪港通、深港通的组合买入

26:组合卖出,或沪港通、深港通的组合卖出

27:融资买入

28:融券卖出

29:买券还券

31:卖券还款

33:信用账号股票买入

34:信用账号股票卖出

40:期货组合开多

43:期货组合开空

46:期货组合平多,优先平今

47:期货组合平多,优先平昨

48:期货组合平空,优先平今

49:期货组合平空,优先平昨

期权交易:

50:买入开仓

51:卖出平仓

52:卖出开仓

53:买入平仓

54:备兑开仓

55:备兑平仓

56:认购行权

57:认沽行权

58:证券锁定

59:证券解锁
它把期货,股票,期权所有品种压缩到一起,通过参数数字来辨认交易类别。
 
那么我们来看一看一个例子,就拿一个官网的一个例子来说:
 
最简单的例子:passorder(23,1101,account,s,11,14.00,100,2,ContextInfo)
一般人看了上面的代码,里面全部是数字,简直就像灾难一样。 但是我要明白它的交易品种和交易逻辑,
就得对着文档去查,编号23是啥,1101是啥,11,14又是啥。
 
如果我是代码reviewer,底下的员工这种文档,或者写代码的人,提交上这样的代码,绝对100%是要reject这个提交的。
 
然后orderType 更加让人吐血。。
 1101:单股、单账号、普通、股/手方式下单

1102:单股、单账号、普通、金额(元)方式下单(只支持股票)

1113:单股、单账号、总资产、比例 [0 ~ 1] 方式下单

1123:单股、单账号、可用、比例[0 ~ 1]方式下单

1201:单股、账号组(无权重)、普通、股/手方式下单

1202:单股、账号组(无权重)、普通、金额(元)方式下单(只支持股票)

1213:单股、账号组(无权重)、总资产、比例 [0 ~ 1] 方式下单

1223:单股、账号组(无权重)、可用、比例 [0 ~ 1] 方式下单

2101:组合、单账号、普通、按组合股票数量(篮子中股票设定的数量)方式下单 > 对应 volume 的单位为篮子的份

2102:组合、单账号、普通、按组合股票权重(篮子中股票设定的权重)方式下单 > 对应 volume 的单位为元

2103:组合、单账号、普通、按账号可用方式下单 > (底层篮子股票怎么分配?答:按可用资金比例后按篮子中股票权重分配,如用户没填权重则按相等权重分配)只对股票篮子支持

2201:组合、账号组(无权重)、普通、按组合股票数量方式下单

2202:组合、账号组(无权重)、普通、按组合股票权重方式下单



这排列组合,谁能记得住,逼着你去查文档,或者每次复制粘贴旧代码。
 
然后下单 类型,继续来各种枚举:
 -1:无效(实际下单时,需要用交易面板交易函数那设定的选价类型)

0:卖5价

1:卖4价

2:卖3价

3:卖2价

4:卖1价

5:最新价

6:买1价

7:买2价(组合不支持)

8:买3价(组合不支持)

9:买4价(组合不支持)

10:买5价(组合不支持)

11:(指定价)模型价(只对单股情况支持,对组合交易不支持)

12:涨跌停价

13:挂单价

14:对手价

27:市价即成剩撤(仅对股票期权申报有效)

28:市价即全成否则撤(仅对股票期权申报有效)

29:市价剩转限价(仅对股票期权申报有效)

42:最优五档即时成交剩余撤销申报(仅对上交所申报有效)

43:最优五档即时成交剩转限价申报(仅对上交所申报有效)

44:对手方最优价格委托(仅对深交所申报有效)

45:本方最优价格委托(仅对深交所申报有效)

46:即时成交剩余撤销委托(仅对深交所申报有效)

47:最优五档即时成交剩余撤销委托(仅对深交所申报有效)

48:全额成交或撤销委托(仅对深交所申报有效)

49:科创板盘后定价
会不会用常量定义个值给客户调用呢?
 passorder(
ContextInfo.TYPE_STOCK,

ContextInfo.TYPE_BUY,
100,
ContextInfo.LIMIT_PRICE,
ContextInfo)
没有标注类型:
虽然python是若类型的语言,可是qmt底层是c++,有些参数不对,就会导致异常:
比如交易软件:
 
比如下单函数passorder的参数列表:
volume,下单数量(股 / 手 / 元 / %)

passorder(opType, orderType, accountID, orderCode, prType, price, volume, ContextInfo)

根据 orderType 值最后一位确定 volume 的单位:

单股下单时:

1:股 / 手

2:金额(元)

3:比例(%)这个类型如果用了浮点,前面类型用了以股为但是,是会报错的,因为不存在100.11 股这样的非100单位的下单数据。
 
看完不想吐槽了,一群文科生设计的软件。。。





  查看全部
在部署QMT 在线文档的时候,还是忍不住吐槽下它的文档。
 这也是当时不用QMT的一个重要原因。
 
不仅仅是文档,而且还有它的函数接口的涉及。
 
比如最常用的交易函数,passorder
综合交易下单 passorder()
用法: passorder(opType, orderType, accountid, orderCode, prType, modelprice, volume[, strategyName, quickTrade, userOrderId], ContextInfo)

里面有11个参数,可选参数有2个。 对于一个常用函数来说,这个参数有点多了。
 
而更为令人费解的,是它参数里面额设定值
比如第一个opType,操作类型。
 
里面有59个数字:
期货六键:

0:开多

1:平昨多

2:平今多

3:开空

4:平昨空

5:平今空

期货四键:

6:平多,优先平今

7:平多,优先平昨

8:平空,优先平今

9:平空,优先平昨

期货两键:

10:卖出,如有多仓,优先平仓,优先平今,如有余量,再开空

11:卖出,如有多仓,优先平仓,优先平昨,如有余量,再开空

12:买入,如有空仓,优先平仓,优先平今,如有余量,再开多

13:买入,如有空仓,优先平仓,优先平昨,如有余量,再开多

14:买入,不优先平仓

15:卖出,不优先平仓

股票买卖:

23:股票买入,或沪港通、深港通股票买入

24:股票卖出,或沪港通、深港通股票卖出

融资融券:

27:融资买入

28:融券卖出

29:买券还券

30:直接还券

31:卖券还款

32:直接还款

33:信用账号股票买入

34:信用账号股票卖出

组合交易:

25:组合买入,或沪港通、深港通的组合买入

26:组合卖出,或沪港通、深港通的组合卖出

27:融资买入

28:融券卖出

29:买券还券

31:卖券还款

33:信用账号股票买入

34:信用账号股票卖出

40:期货组合开多

43:期货组合开空

46:期货组合平多,优先平今

47:期货组合平多,优先平昨

48:期货组合平空,优先平今

49:期货组合平空,优先平昨

期权交易:

50:买入开仓

51:卖出平仓

52:卖出开仓

53:买入平仓

54:备兑开仓

55:备兑平仓

56:认购行权

57:认沽行权

58:证券锁定

59:证券解锁

它把期货,股票,期权所有品种压缩到一起,通过参数数字来辨认交易类别。
 
那么我们来看一看一个例子,就拿一个官网的一个例子来说:
 
最简单的例子:
passorder(23,1101,account,s,11,14.00,100,2,ContextInfo)

一般人看了上面的代码,里面全部是数字,简直就像灾难一样。 但是我要明白它的交易品种和交易逻辑,
就得对着文档去查,编号23是啥,1101是啥,11,14又是啥。
 
如果我是代码reviewer,底下的员工这种文档,或者写代码的人,提交上这样的代码,绝对100%是要reject这个提交的。
 
然后orderType 更加让人吐血。。
 
1101:单股、单账号、普通、股/手方式下单

1102:单股、单账号、普通、金额(元)方式下单(只支持股票)

1113:单股、单账号、总资产、比例 [0 ~ 1] 方式下单

1123:单股、单账号、可用、比例[0 ~ 1]方式下单

1201:单股、账号组(无权重)、普通、股/手方式下单

1202:单股、账号组(无权重)、普通、金额(元)方式下单(只支持股票)

1213:单股、账号组(无权重)、总资产、比例 [0 ~ 1] 方式下单

1223:单股、账号组(无权重)、可用、比例 [0 ~ 1] 方式下单

2101:组合、单账号、普通、按组合股票数量(篮子中股票设定的数量)方式下单 > 对应 volume 的单位为篮子的份

2102:组合、单账号、普通、按组合股票权重(篮子中股票设定的权重)方式下单 > 对应 volume 的单位为元

2103:组合、单账号、普通、按账号可用方式下单 > (底层篮子股票怎么分配?答:按可用资金比例后按篮子中股票权重分配,如用户没填权重则按相等权重分配)只对股票篮子支持

2201:组合、账号组(无权重)、普通、按组合股票数量方式下单

2202:组合、账号组(无权重)、普通、按组合股票权重方式下单



这排列组合,谁能记得住,逼着你去查文档,或者每次复制粘贴旧代码。
 
然后下单 类型,继续来各种枚举:
 
-1:无效(实际下单时,需要用交易面板交易函数那设定的选价类型)

0:卖5价

1:卖4价

2:卖3价

3:卖2价

4:卖1价

5:最新价

6:买1价

7:买2价(组合不支持)

8:买3价(组合不支持)

9:买4价(组合不支持)

10:买5价(组合不支持)

11:(指定价)模型价(只对单股情况支持,对组合交易不支持)

12:涨跌停价

13:挂单价

14:对手价

27:市价即成剩撤(仅对股票期权申报有效)

28:市价即全成否则撤(仅对股票期权申报有效)

29:市价剩转限价(仅对股票期权申报有效)

42:最优五档即时成交剩余撤销申报(仅对上交所申报有效)

43:最优五档即时成交剩转限价申报(仅对上交所申报有效)

44:对手方最优价格委托(仅对深交所申报有效)

45:本方最优价格委托(仅对深交所申报有效)

46:即时成交剩余撤销委托(仅对深交所申报有效)

47:最优五档即时成交剩余撤销委托(仅对深交所申报有效)

48:全额成交或撤销委托(仅对深交所申报有效)

49:科创板盘后定价

会不会用常量定义个值给客户调用呢?
 
passorder(
ContextInfo.TYPE_STOCK,

ContextInfo.TYPE_BUY,
100,
ContextInfo.LIMIT_PRICE,
ContextInfo)

没有标注类型:
虽然python是若类型的语言,可是qmt底层是c++,有些参数不对,就会导致异常:
比如交易软件:
 
比如下单函数passorder的参数列表:
volume,下单数量(股 / 手 / 元 / %)

passorder(opType, orderType, accountID, orderCode, prType, price, volume, ContextInfo)

根据 orderType 值最后一位确定 volume 的单位:

单股下单时:

1:股 / 手

2:金额(元)

3:比例(%)
这个类型如果用了浮点,前面类型用了以股为但是,是会报错的,因为不存在100.11 股这样的非100单位的下单数据。
 
看完不想吐槽了,一群文科生设计的软件。。。

3fc3af7e327ac67c475223f8424004fd.jpg

 

为什么我的QMT安装目录下没有miniqmt的包xtquant

QMT李魔佛 发表了文章 • 0 个评论 • 1100 次浏览 • 2023-02-20 21:00 • 来自相关话题

今天有位群友,qmt新手,说看了我的公众号,想搞miniQMT,结果发现安装了国盛的QMT之后没有发现xtquant的目录。





 



 
他安装的也是实盘正式版本的QMT。
 
那么问题出现在哪里呢?
 
主要问题在于它没有在qmt内部 下载内置的python库。
 





 
经过这个下载过程后。
 
然后就可以看到有site-packages了





 

 
  查看全部
今天有位群友,qmt新手,说看了我的公众号,想搞miniQMT,结果发现安装了国盛的QMT之后没有发现xtquant的目录。

20230220185141623.png

 
20230220012.jpg

 
他安装的也是实盘正式版本的QMT。
 
那么问题出现在哪里呢?
 
主要问题在于它没有在qmt内部 下载内置的python库。
 

mmexport1676896038788.png

 
经过这个下载过程后。
 
然后就可以看到有site-packages了

20230220013.jpg

 

 
 

qmt iquant最新接口文档

QMT李魔佛 发表了文章 • 0 个评论 • 1328 次浏览 • 2023-02-19 15:16 • 来自相关话题

申请了个二级域名,作为QMT iQuant的接口文档。懒得再去搞新的域名了,凑合这用,和ptrade的接口文档拼在一个根域名下面
 
http://qmt.ptradeapi.com





 





 





 
除了官方的接口文档,还加入了一些个人平时编写的写法与回测,实盘代码。 不定期更新。
 
欢迎关注收藏。 查看全部
申请了个二级域名,作为QMT iQuant的接口文档。懒得再去搞新的域名了,凑合这用,和ptrade的接口文档拼在一个根域名下面
 
http://qmt.ptradeapi.com

20230219003.jpg

 

20230219004.jpg

 

20230219005.jpg

 
除了官方的接口文档,还加入了一些个人平时编写的写法与回测,实盘代码。 不定期更新。
 
欢迎关注收藏。

整理一批 注册好的免费chatGPT账户,从分享群里获取的,亲测有效

网络马化云 发表了文章 • 0 个评论 • 3463 次浏览 • 2023-02-16 12:51 • 来自相关话题

 
请勿随意修改密码: ChatGPT共享账号
账号1:vickye89@hotmail.com
密码:LeZ25X5dwL
账号2:eugeniev552@hotmail.com
密码2:4w95MnvIvc
账号3:ayakonewuyo@hotmail.com
密码3:q8UCd2lST4
账号4:ludmillasteb9@hotmail.com
密码4:7sb54Oii8I
账号5:chr89kuchto@hotmail.com
密码5:Cea7IQj5ud
账号6:emil03mk@hotmail.com
密码6:ENC82hip2A
账号7:lydiavn9ktutoky@hotmail.com
密码7:6351VsZz25
账号8:tulagj3@hotmail.com
密码8:Wx99eCqer7
账号9:prue56zjehle@hotmail.com
密码9:8398k84X85
账号10:vernitagq2@hotmail.com
密码10:geFfr4H0x9
账号11:kirstiealtqw@hotmail.com
密码11:1FBbV8OJg9
账号12:ralphnamer32d@hotmail.com
密码12:F85T86YtbL
账号13:celinabullievmu@hotmail.com
密码13:OqTz0lj525
账号14:chanafdidelaet@hotmail.com
密码14:6x3CM4pPYY
账号15:alita07pbogdon@hotmail.com
密码15:Umppl1ylc0
账号16:averilltxgt@hotmail.com
密码16:94cymN2p42
账号17:mobyfotohy7@hotmail.com
密码17:c8iJi0Fd
账号18:muficylequ9@hotmail.com
密码18:5p0KWJf1D
账号19:naehahogujo0@hotmail.com
密码19:xgH5o3jKV
账号20:naejexelibu@hotmail.com
密码20:fZg44fVeh
账号21:naezhaeshequsito@outlook.com
密码21:PtRbh31IF
账号22:neladeroka@hotmail.com
密码22:McTk3Qrz
账号23:pyvohywaeli@outlook.com
密码23:Ehk9d5QFz4
账号24:qadakidone@hotmail.com
密码24:I836s6941q
账号25:qaraesisheby9@hotmail.com
密码25:UQkJim80c
账号26:qaxiberasipy@outlook.com
密码26:XVYluIYy2P
账号27:qeluzhaelagy4@hotmail.com
密码27:8qZEl20fR
账号28:qobiluno7@hotmail.com
密码28:4KiM2C0q9
账号29:qupipaeshe1@outlook.com
密码29:4j9NSpGHEZ
账号30:qyshymisifi0@hotmail.com
密码30:Sfp9D0UNK4
账号31:raehotushawo@hotmail.com
密码31:2d0H8o9L




https://chat.openai.com/auth/login​
ChatGPT登录地址 ChatGPT
 
需要配合梯子使用,效果更佳。
如果显示:






就是要搭梯子了
 
更多数据,请关注公众号,后台回复:chatgpt账户 查看全部
20230216001.jpg

 
请勿随意修改密码: 
ChatGPT共享账号
账号1:vickye89@hotmail.com
密码:LeZ25X5dwL
账号2:eugeniev552@hotmail.com
密码2:4w95MnvIvc
账号3:ayakonewuyo@hotmail.com
密码3:q8UCd2lST4
账号4:ludmillasteb9@hotmail.com
密码4:7sb54Oii8I
账号5:chr89kuchto@hotmail.com
密码5:Cea7IQj5ud
账号6:emil03mk@hotmail.com
密码6:ENC82hip2A
账号7:lydiavn9ktutoky@hotmail.com
密码7:6351VsZz25
账号8:tulagj3@hotmail.com
密码8:Wx99eCqer7
账号9:prue56zjehle@hotmail.com
密码9:8398k84X85
账号10:vernitagq2@hotmail.com
密码10:geFfr4H0x9
账号11:kirstiealtqw@hotmail.com
密码11:1FBbV8OJg9
账号12:ralphnamer32d@hotmail.com
密码12:F85T86YtbL
账号13:celinabullievmu@hotmail.com
密码13:OqTz0lj525
账号14:chanafdidelaet@hotmail.com
密码14:6x3CM4pPYY
账号15:alita07pbogdon@hotmail.com
密码15:Umppl1ylc0
账号16:averilltxgt@hotmail.com
密码16:94cymN2p42
账号17:mobyfotohy7@hotmail.com
密码17:c8iJi0Fd
账号18:muficylequ9@hotmail.com
密码18:5p0KWJf1D
账号19:naehahogujo0@hotmail.com
密码19:xgH5o3jKV
账号20:naejexelibu@hotmail.com
密码20:fZg44fVeh
账号21:naezhaeshequsito@outlook.com
密码21:PtRbh31IF
账号22:neladeroka@hotmail.com
密码22:McTk3Qrz
账号23:pyvohywaeli@outlook.com
密码23:Ehk9d5QFz4
账号24:qadakidone@hotmail.com
密码24:I836s6941q
账号25:qaraesisheby9@hotmail.com
密码25:UQkJim80c
账号26:qaxiberasipy@outlook.com
密码26:XVYluIYy2P
账号27:qeluzhaelagy4@hotmail.com
密码27:8qZEl20fR
账号28:qobiluno7@hotmail.com
密码28:4KiM2C0q9
账号29:qupipaeshe1@outlook.com
密码29:4j9NSpGHEZ
账号30:qyshymisifi0@hotmail.com
密码30:Sfp9D0UNK4
账号31:raehotushawo@hotmail.com
密码31:2d0H8o9L




https://chat.openai.com/auth/login​
ChatGPT登录地址 ChatGPT
 
需要配合梯子使用,效果更佳。
如果显示:

20230216002.jpg


就是要搭梯子了
 
更多数据,请关注公众号,后台回复:chatgpt账户

【白嫖服务器】render.com上部署flask程序

网络马化云 发表了文章 • 0 个评论 • 1195 次浏览 • 2023-02-14 15:43 • 来自相关话题

要在Render.com上部署Flask应用程序,可以按照以下步骤进行操作:
1. 注册Render.com帐户并创建一个新的Web服务。

2. 在“添加服务”页面上选择“Web服务”并选择“自定义”作为服务类型。
 
3. 选择一个适合您的Flask应用程序的服务器和端口。
 
4. 在“高级”选项卡中添加一个名为“WEB_COMMAND”的环境变量,其值为“gunicorn your_app_name:app”(替换your_app_name为您的应用程序名称)。
 
5. 在“高级”选项卡中添加一个名为“WEB_CONCURRENCY”的环境变量,其值为应用程序的工作进程数(例如2)。
 
6. 将您的Flask应用程序代码推送到GitHub或其他源代码管理库中,并将其链接到Render.com服务。
 
7. 等待几分钟,Render.com将自动构建和部署您的Flask应用程序。

完成以上步骤后,您的Flask应用程序将已经成功部署在Render.com上。
 
示例代码:from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'上面是app.py 的内容
 




 
同步到github上后,绑定域名,运行得到: 





 
是不是很简单呢?
 
网站可以免费解析25个域名,超过的需要收费。不过一般人应该不会超过那么多的域名的了吧。
 

Starting February 1, 2022, we will begin charging $0.60 per custom domain per month beyond the first 25 custom domains for a web service or static site. The first 25 custom domains for web services and static sites will continue to be free.


 
 
 
  查看全部
要在Render.com上部署Flask应用程序,可以按照以下步骤进行操作:
1. 注册Render.com帐户并创建一个新的Web服务。

2. 在“添加服务”页面上选择“Web服务”并选择“自定义”作为服务类型。
 
3. 选择一个适合您的Flask应用程序的服务器和端口。
 
4. 在“高级”选项卡中添加一个名为“WEB_COMMAND”的环境变量,其值为“gunicorn your_app_name:app”(替换your_app_name为您的应用程序名称)。
 
5. 在“高级”选项卡中添加一个名为“WEB_CONCURRENCY”的环境变量,其值为应用程序的工作进程数(例如2)。
 
6. 将您的Flask应用程序代码推送到GitHub或其他源代码管理库中,并将其链接到Render.com服务。
 
7. 等待几分钟,Render.com将自动构建和部署您的Flask应用程序。

完成以上步骤后,您的Flask应用程序将已经成功部署在Render.com上。
 
示例代码:
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'
上面是app.py 的内容
 
20230214004.jpg

 
同步到github上后,绑定域名,运行得到: 

20230214006.jpg

 
是不是很简单呢?
 
网站可以免费解析25个域名,超过的需要收费。不过一般人应该不会超过那么多的域名的了吧。
 


Starting February 1, 2022, we will begin charging $0.60 per custom domain per month beyond the first 25 custom domains for a web service or static site. The first 25 custom domains for web services and static sites will continue to be free.



 
 
 
 

迅投qmt入门教程(一)

QMT李魔佛 发表了文章 • 0 个评论 • 7994 次浏览 • 2023-02-06 19:43 • 来自相关话题

很早想写一个qmt教程的,无奈平时90%时间都用的ptrade。之前想把教程写好了再发出来,不过这样只会越拖越久,为了让自己填这个坑,先把文章发出来,按照平时正常的量化学习的路径,从简单到复杂。 慢慢记录,形成个系列教程。 有疑问的朋友可以到笔者的公众号或者知识星球去提问吧。(见文末)
 
1. 准备:
 
首先得开一个支持qmt的券商,目前市面上支持qmt的券商越来越丰富了。
 
初学者可以开一个门槛第一点的,一般入金1w-2w 不等,就可以申请开通了。 
 
鉴于以学习为目的,真正投入到实盘中的资金不会很大,所以初始阶段也不一定就找万一免五的券商,毕竟目前要给免五,资金门槛比较高,一般要100w甚至以上。
 
笔者推荐国信,国金的qmt, 门槛只要1-2w就足够了,股票费率在万一,可转债万0.4-万0.5。适合初学者,这两家也可以在虚拟机运行,适合苹果mac的用户。 需要的朋友也可以在公众号后台留言: qmt开通





 
2. 假设已经在券商那里开通了qmt功能,接下来就开始进入教学:
 
这里以国信的qmt(iquant)为例:
 
首先要做的就是下载python库。 这个python库指的是qmt的python库,它的版本是3.6.8; 如果你只用qmt内置的python,你就不用自己到网上下载python安装程序,只需要在qmt的设置里面,点一下按钮,就可以安装python库。这里用默认的系统路径就可以了。
 





 
3. 第一个量化程序 hello world
 
新建策略后:
在编辑器里面输入下面的代码:#encoding:gbk

def init(ContextInfo):
print('hello world')

def handlebar(ContextInfo):
#计算当前主图的cci
print("handle bar")
点击回测:
得到输出结果




 
这里介绍2个概念:(3)Handlebar

handlebar 是整个 Python 模型中的核心执行函数。当模型从数据层获取到运行所需要的数据之后,会对数据集上的每一根 bar,调用一次 handlebar 函数,处理当前这根 bar 上的数据。也就是说,用户模型的核心逻辑都是写在该函数中的,如获取数据,设置下单条件等。在 handlebar 中处理完数据后,用户可以通过 paint 方法将需要绘图输出的结果返回给界面。界面会将输出结果如实的展示出来。 (4)ContextInfo

ContextInfo 是整个 Python 框架中的一个核心对象。它包含了各种与 Python 底层框架交互的 API 方法,也是一个全局的上下文环境,可以在 init 以及 handlebar 这两个函数中自由地传递用户创建的各种自定义数据。





文绉绉的,实际写一个策略,必须包含下面两个函数,而且参数也要一致,参数名随意,不过用默认的就好了。你随便改成没有意义的字符,后面自己看代码也是很麻烦。def init(ContextInfo):
pass

def handlebar(ContextInfo):
pass
 
init 和 handlebar 是 Python 模型中最重要的方法,也是唯二由 C++ 直接调用的方法,所有的执行代码都尽量写在这两个方法中或由其中的函数调用。【个人不太喜欢这样】
 
回测时间设置,在右边的菜单栏,有个回测参数,里面设置时间;在菜单“基本信息”里面 ,可以设置回测的时间间隔,可以使用分钟线,日线,小时等等不同周期,不过无法做到tick的回测。最小的只能到分钟。
 
但是如果你有秒的tick数据,自己写个回测框架也是可以做到秒级的tick级别的回测。很早前笔者就在星球上提供了完整的源码和数据,初学者也可以拿着去改,只要后续更新tick数据,就可以不断的回测策略的最新状态。
 
你写的回测实盘python代码,是保存在本地的文件夹的:
C:\iquant_gx\python, 前面的C:\iquant_gx 是你的iquant安装路径。
 
而且底下也有很多的现成的代码:





 
部分代码可以直接用pycharm就可以打开,没有加密的,但也有一些是加密了的。
比如这个自动逆回购是现成的:





对,这里就有,很多人还到处找人写;# encoding:gbk
import logging
from datetime import datetime, timedelta
from decimal import Decimal as D
from decimal import InvalidOperation

logging.basicConfig(level=logging.INFO)

# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 等待account_callback的时长
# RUN_TIME_DELAY = 30

# how is this not defined in package??
MORNING_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '093000', '%Y%m%d%H%M%S')
MORNING_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '113000', '%Y%m%d%H%M%S')
NOON_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '130000', '%Y%m%d%H%M%S')
NOON_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '153000', '%Y%m%d%H%M%S')

# for SH only
TRANS_COST_1D = D('5e-6')
TRANS_COST_LONG = D('1.5e-7')
TRANS_COST_MAX = 100

# ORDER LIMITS
SH_UPPER = 1e7
SH_LOWER = 1e5
SZ_UPPER = 1e8
SZ_LOWER = 1e3

# ASSET NAME DICT
SH_REV_REPO = {'上交所1天': '204001.SH', '上交所2天': '204002.SH', '上交所3天': '204003.SH',
'上交所4天': '204004.SH', '上交所7天': '204007.SH', '上交所14天': '204014.SH',
'上交所28天': '204028.SH', '上交所91天': '204091.SH', '上交所182天': '204182.SH',
}

SZ_REV_REPO = {'深交所3天': '131800.SZ', '深交所7天': '131801.SZ', '深交所14天': '131802.SZ',
'深交所28天': '131803.SZ', '深交所91天': '131805.SZ', '深交所182天': '131806.SZ',
'深交所4天': '131809.SZ', '深交所1天': '131810.SZ', '深交所2天': '131811.SZ',
}


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)
ContextInfo.use_all_cap = False if ALL_CAP == '否' else True

# global trading control, set to False if detected error on user's side
# stop() does not halt strat
ContextInfo.order_control = False

if not ContextInfo.use_all_cap:
try:
ContextInfo.dollar_vol = float(D(DOLLAR_VOL))
except InvalidOperation:
ContextInfo.order_control = True
raise ValueError('读取资金量失败')
else:
if DOLLAR_VOL != '':
logging.warning('已设定使用全部账户资金,忽略所设置资金量')

try:
ContextInfo.start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
ContextInfo.asset_name = SH_REV_REPO[ASSET_NAME]
except KeyError:
ContextInfo.asset_name = SZ_REV_REPO[ASSET_NAME]
except ValueError as error:
if 'unconverted data remains' in str(error):
ContextInfo.order_control = True
raise ValueError('读取挂单时间失败')

if not (MORNING_END > ContextInfo.start_time >= MORNING_START) \
and not (NOON_END > ContextInfo.start_time >= NOON_START):
ContextInfo.order_control = True
raise ValueError('挂单时间不在可交易时间内')

ContextInfo.can_order = False
ContextInfo.order_done = False

if not ContextInfo.order_control:
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
ContextInfo.start_time.strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True
if ContextInfo.use_all_cap:
ContextInfo.dollar_vol = accountInfo.m_dAvailable
else:
if ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('下单额度大于账户可用资金')

# check if order satisfies lower limit for each exchange
if ('SH' in ContextInfo.asset_name and ContextInfo.dollar_vol < SH_LOWER) \
or ('SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol < SZ_LOWER):
ContextInfo.order_control = True
raise ValueError('下单额度低于交易所最低限额')

# checks dollar_vol and rounds the total amount
if 'SH' in ContextInfo.asset_name and ContextInfo.dollar_vol % SH_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SH_LOWER) * SH_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))
elif 'SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol % SZ_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SZ_LOWER) * SZ_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))

'''
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.dollar_vol // SH_UPPER)
remain_order = ContextInfo.dollar_vol - num_batch_order * SH_UPPER
if ContextInfo.asset_name == '204001.SH':
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_1D
else:
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_LONG
if transaction_cost + ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('可用资金不足以垫付交易金额与手续费')
'''

ContextInfo.remain_vol = ContextInfo.dollar_vol


def handlebar(ContextInfo):
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.order_control:
return

if not ContextInfo.order_done:
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.remain_vol // SH_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SH_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SH_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SH_UPPER, order_remark, 1,
order_remark, ContextInfo)
else:
num_batch_order = int(ContextInfo.remain_vol // SZ_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SZ_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SZ_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SZ_UPPER, order_remark, 1,
order_remark, ContextInfo)

order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(remain_order, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, remain_order, order_remark, 1,
order_remark, ContextInfo)

ContextInfo.remain_vol = 0
ContextInfo.order_done = True


def order_callback(ContextInfo, orderInfo):
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus

if '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 57:
ContextInfo.order_done = False
# up the leftover dollar vol by failed amount
# logging.info('reported trade amount:{0}, reported_trade_volume:{1}'.format(orderInfo.m_dTradeAmount, orderInfo.m_nVolumeTotal))
# 单张100元
ContextInfo.remain_vol += orderInfo.m_nVolumeTotal * 100
if '交易时间不合法' in orderInfo.m_strCancelInfo:
ContextInfo.order_control = True
raise ValueError('国债逆回购:未能在交易时间内完成下单,停止报单。余量{0}元未报'.format(ContextInfo.remain_vol))
logging.warning('国债逆回购:报单废单,原因:\"{0}\",尝试重报'.format(orderInfo.m_strCancelInfo))
elif '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 50:
logging.info('国债逆回购:报单{0}元成功'.format(orderInfo.m_nVolumeTotal * 100))
return




待续,不定期更新


 
 
公众号:

星球:

 
 
 
  查看全部
很早想写一个qmt教程的,无奈平时90%时间都用的ptrade。之前想把教程写好了再发出来,不过这样只会越拖越久,为了让自己填这个坑,先把文章发出来,按照平时正常的量化学习的路径,从简单到复杂。 慢慢记录,形成个系列教程。 有疑问的朋友可以到笔者的公众号或者知识星球去提问吧。(见文末)
 
1. 准备:
 
首先得开一个支持qmt的券商,目前市面上支持qmt的券商越来越丰富了。
 
初学者可以开一个门槛第一点的,一般入金1w-2w 不等,就可以申请开通了。 
 
鉴于以学习为目的,真正投入到实盘中的资金不会很大,所以初始阶段也不一定就找万一免五的券商,毕竟目前要给免五,资金门槛比较高,一般要100w甚至以上。
 
笔者推荐国信,国金的qmt, 门槛只要1-2w就足够了,股票费率在万一,可转债万0.4-万0.5。适合初学者,这两家也可以在虚拟机运行,适合苹果mac的用户。 需要的朋友也可以在公众号后台留言: qmt开通

20230206005.jpg

 
2. 假设已经在券商那里开通了qmt功能,接下来就开始进入教学:
 
这里以国信的qmt(iquant)为例:
 
首先要做的就是下载python库。 这个python库指的是qmt的python库,它的版本是3.6.8; 如果你只用qmt内置的python,你就不用自己到网上下载python安装程序,只需要在qmt的设置里面,点一下按钮,就可以安装python库。这里用默认的系统路径就可以了。
 

20230206006.jpg

 
3. 第一个量化程序 hello world
 
新建策略后:
在编辑器里面输入下面的代码:
#encoding:gbk

def init(ContextInfo):
print('hello world')

def handlebar(ContextInfo):
#计算当前主图的cci
print("handle bar")

点击回测:
得到输出结果
20230206007.jpg

 
这里介绍2个概念:
(3)Handlebar

handlebar 是整个 Python 模型中的核心执行函数。当模型从数据层获取到运行所需要的数据之后,会对数据集上的每一根 bar,调用一次 handlebar 函数,处理当前这根 bar 上的数据。也就是说,用户模型的核心逻辑都是写在该函数中的,如获取数据,设置下单条件等。在 handlebar 中处理完数据后,用户可以通过 paint 方法将需要绘图输出的结果返回给界面。界面会将输出结果如实的展示出来。
 
(4)ContextInfo

ContextInfo 是整个 Python 框架中的一个核心对象。它包含了各种与 Python 底层框架交互的 API 方法,也是一个全局的上下文环境,可以在 init 以及 handlebar 这两个函数中自由地传递用户创建的各种自定义数据。





文绉绉的,实际写一个策略,必须包含下面两个函数,而且参数也要一致,参数名随意,不过用默认的就好了。你随便改成没有意义的字符,后面自己看代码也是很麻烦。
def init(ContextInfo):
pass

def handlebar(ContextInfo):
pass

 
init 和 handlebar 是 Python 模型中最重要的方法,也是唯二由 C++ 直接调用的方法,所有的执行代码都尽量写在这两个方法中或由其中的函数调用。【个人不太喜欢这样】
 
回测时间设置,在右边的菜单栏,有个回测参数,里面设置时间;在菜单“基本信息”里面 ,可以设置回测的时间间隔,可以使用分钟线,日线,小时等等不同周期,不过无法做到tick的回测。最小的只能到分钟。
 
但是如果你有秒的tick数据,自己写个回测框架也是可以做到秒级的tick级别的回测。很早前笔者就在星球上提供了完整的源码和数据,初学者也可以拿着去改,只要后续更新tick数据,就可以不断的回测策略的最新状态。
 
你写的回测实盘python代码,是保存在本地的文件夹的:
C:\iquant_gx\python, 前面的C:\iquant_gx 是你的iquant安装路径。
 
而且底下也有很多的现成的代码:

20230206008.jpg

 
部分代码可以直接用pycharm就可以打开,没有加密的,但也有一些是加密了的。
比如这个自动逆回购是现成的:

20230206010.jpg

对,这里就有,很多人还到处找人写;
# encoding:gbk
import logging
from datetime import datetime, timedelta
from decimal import Decimal as D
from decimal import InvalidOperation

logging.basicConfig(level=logging.INFO)

# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 等待account_callback的时长
# RUN_TIME_DELAY = 30

# how is this not defined in package??
MORNING_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '093000', '%Y%m%d%H%M%S')
MORNING_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '113000', '%Y%m%d%H%M%S')
NOON_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '130000', '%Y%m%d%H%M%S')
NOON_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '153000', '%Y%m%d%H%M%S')

# for SH only
TRANS_COST_1D = D('5e-6')
TRANS_COST_LONG = D('1.5e-7')
TRANS_COST_MAX = 100

# ORDER LIMITS
SH_UPPER = 1e7
SH_LOWER = 1e5
SZ_UPPER = 1e8
SZ_LOWER = 1e3

# ASSET NAME DICT
SH_REV_REPO = {'上交所1天': '204001.SH', '上交所2天': '204002.SH', '上交所3天': '204003.SH',
'上交所4天': '204004.SH', '上交所7天': '204007.SH', '上交所14天': '204014.SH',
'上交所28天': '204028.SH', '上交所91天': '204091.SH', '上交所182天': '204182.SH',
}

SZ_REV_REPO = {'深交所3天': '131800.SZ', '深交所7天': '131801.SZ', '深交所14天': '131802.SZ',
'深交所28天': '131803.SZ', '深交所91天': '131805.SZ', '深交所182天': '131806.SZ',
'深交所4天': '131809.SZ', '深交所1天': '131810.SZ', '深交所2天': '131811.SZ',
}


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)
ContextInfo.use_all_cap = False if ALL_CAP == '否' else True

# global trading control, set to False if detected error on user's side
# stop() does not halt strat
ContextInfo.order_control = False

if not ContextInfo.use_all_cap:
try:
ContextInfo.dollar_vol = float(D(DOLLAR_VOL))
except InvalidOperation:
ContextInfo.order_control = True
raise ValueError('读取资金量失败')
else:
if DOLLAR_VOL != '':
logging.warning('已设定使用全部账户资金,忽略所设置资金量')

try:
ContextInfo.start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
ContextInfo.asset_name = SH_REV_REPO[ASSET_NAME]
except KeyError:
ContextInfo.asset_name = SZ_REV_REPO[ASSET_NAME]
except ValueError as error:
if 'unconverted data remains' in str(error):
ContextInfo.order_control = True
raise ValueError('读取挂单时间失败')

if not (MORNING_END > ContextInfo.start_time >= MORNING_START) \
and not (NOON_END > ContextInfo.start_time >= NOON_START):
ContextInfo.order_control = True
raise ValueError('挂单时间不在可交易时间内')

ContextInfo.can_order = False
ContextInfo.order_done = False

if not ContextInfo.order_control:
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
ContextInfo.start_time.strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True
if ContextInfo.use_all_cap:
ContextInfo.dollar_vol = accountInfo.m_dAvailable
else:
if ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('下单额度大于账户可用资金')

# check if order satisfies lower limit for each exchange
if ('SH' in ContextInfo.asset_name and ContextInfo.dollar_vol < SH_LOWER) \
or ('SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol < SZ_LOWER):
ContextInfo.order_control = True
raise ValueError('下单额度低于交易所最低限额')

# checks dollar_vol and rounds the total amount
if 'SH' in ContextInfo.asset_name and ContextInfo.dollar_vol % SH_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SH_LOWER) * SH_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))
elif 'SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol % SZ_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SZ_LOWER) * SZ_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))

'''
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.dollar_vol // SH_UPPER)
remain_order = ContextInfo.dollar_vol - num_batch_order * SH_UPPER
if ContextInfo.asset_name == '204001.SH':
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_1D
else:
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_LONG
if transaction_cost + ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('可用资金不足以垫付交易金额与手续费')
'''

ContextInfo.remain_vol = ContextInfo.dollar_vol


def handlebar(ContextInfo):
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.order_control:
return

if not ContextInfo.order_done:
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.remain_vol // SH_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SH_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SH_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SH_UPPER, order_remark, 1,
order_remark, ContextInfo)
else:
num_batch_order = int(ContextInfo.remain_vol // SZ_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SZ_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SZ_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SZ_UPPER, order_remark, 1,
order_remark, ContextInfo)

order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(remain_order, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, remain_order, order_remark, 1,
order_remark, ContextInfo)

ContextInfo.remain_vol = 0
ContextInfo.order_done = True


def order_callback(ContextInfo, orderInfo):
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus

if '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 57:
ContextInfo.order_done = False
# up the leftover dollar vol by failed amount
# logging.info('reported trade amount:{0}, reported_trade_volume:{1}'.format(orderInfo.m_dTradeAmount, orderInfo.m_nVolumeTotal))
# 单张100元
ContextInfo.remain_vol += orderInfo.m_nVolumeTotal * 100
if '交易时间不合法' in orderInfo.m_strCancelInfo:
ContextInfo.order_control = True
raise ValueError('国债逆回购:未能在交易时间内完成下单,停止报单。余量{0}元未报'.format(ContextInfo.remain_vol))
logging.warning('国债逆回购:报单废单,原因:\"{0}\",尝试重报'.format(orderInfo.m_strCancelInfo))
elif '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 50:
logging.info('国债逆回购:报单{0}元成功'.format(orderInfo.m_nVolumeTotal * 100))
return




待续,不定期更新


 
 
公众号:

星球:

 
 
 
 

qmt界面的运行和回测按钮功能有什么不同?

QMT李魔佛 发表了文章 • 0 个评论 • 1060 次浏览 • 2023-02-06 19:00 • 来自相关话题

他们二者的区别:
 
在模型编辑器中,有“回测”和“运行”两个按钮,分别代表两种模式,它们之间的区别如下:
(1)回测模式指策略以历史行情为依据,以回测参数中的开始时间、结束时间为回测时间区间进行运
算,投资者可观察该策略在历史行情所获得的年化收益率、夏普比率、最大回撤、信息比率等指标表
现。

(2)运行模式指策略根据实时行情信号进行运算,以主图行情开始时间到当前时间为运行区间,进行策
略的模拟运行,但不进行真实的委托。

注:如果需要向模拟/实盘柜台发送真实的委托,请将策略加入到“模型交易”中。
盘后运行可能会有抽风现象。

回测的时候日期问题,只能选副图,不知道为何 查看全部

20230206004.jpg

他们二者的区别:
 
在模型编辑器中,有“回测”和“运行”两个按钮,分别代表两种模式,它们之间的区别如下:
(1)回测模式指策略以历史行情为依据,以回测参数中的开始时间、结束时间为回测时间区间进行运
算,投资者可观察该策略在历史行情所获得的年化收益率、夏普比率、最大回撤、信息比率等指标表
现。

(2)运行模式指策略根据实时行情信号进行运算,以主图行情开始时间到当前时间为运行区间,进行策
略的模拟运行,但不进行真实的委托。

注:如果需要向模拟/实盘柜台发送真实的委托,请将策略加入到“模型交易”中。
盘后运行可能会有抽风现象。

回测的时候日期问题,只能选副图,不知道为何

Ptrade基本期货策略

Ptrade李魔佛 发表了文章 • 0 个评论 • 1095 次浏览 • 2023-02-04 14:17 • 来自相关话题

ptrade本身支持期货交易,开通账户绑定就可以了。
新建策略的时候选择:期货即可。





 
 
 1. 买入开仓
 
不同期货品种每一跳的价格变动都不一样,limit_price入参的时候要参考对应品种的价格变动规则,如limit_price不做入参则会以交易的行情快照最新价或者回测的分钟最新价进行报单;

根据交易所规则,每天结束时会取消所有未完成交易;
 
 
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#买入开仓
buy_open('IF1712.CCFX', 1)

#买入开仓(限定点数为52220)
buy_open('CU1806.XSGE', 1, limit_price=52220)
2. 卖出平仓
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#卖出平仓
sell_close('IF1712.CCFX', 1)
#卖出平今仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220, close_today=True)
#卖出平仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220)
3. 获取合约信息
get_instruments- 获取合约信息
 
get_instruments(contract)


返回

FutureParams对象,主要返回的字段为:

contract_code -- 合约代码,str类型;
contract_name -- 合约名称,str类型;
exchange -- 交易所:大商所、郑商所、上期所、中金所,str类型;
trade_unit -- 交易单位,int类型;
contract_multiplier -- 合约乘数,float类型;
delivery_date -- 交割日期,str类型;
listing_date -- 上市日期,str类型;
trade_code -- 交易代码,str类型;
margin_rate -- 保证金比例,float类型;

 
代码示例:
def initialize(context):
g.security = ["CU2112.XSGE", "IF2112.CCFX"]
set_universe(g.security)

def before_trading_start(context, data):
# 获取股票池代码合约信息
for security in g.security:
info = get_instruments(security)
log.info(info)

def handle_data(context, data):
pass 查看全部
ptrade本身支持期货交易,开通账户绑定就可以了。
新建策略的时候选择:期货即可。

20230204005.jpg

 
 
 1. 买入开仓
 
不同期货品种每一跳的价格变动都不一样,limit_price入参的时候要参考对应品种的价格变动规则,如limit_price不做入参则会以交易的行情快照最新价或者回测的分钟最新价进行报单;

根据交易所规则,每天结束时会取消所有未完成交易;
 
 
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#买入开仓
buy_open('IF1712.CCFX', 1)

#买入开仓(限定点数为52220)
buy_open('CU1806.XSGE', 1, limit_price=52220)

2. 卖出平仓
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#卖出平仓
sell_close('IF1712.CCFX', 1)
#卖出平今仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220, close_today=True)
#卖出平仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220)

3. 获取合约信息
get_instruments- 获取合约信息
 
get_instruments(contract)


返回

FutureParams对象,主要返回的字段为:

contract_code -- 合约代码,str类型;
contract_name -- 合约名称,str类型;
exchange -- 交易所:大商所、郑商所、上期所、中金所,str类型;
trade_unit -- 交易单位,int类型;
contract_multiplier -- 合约乘数,float类型;
delivery_date -- 交割日期,str类型;
listing_date -- 上市日期,str类型;
trade_code -- 交易代码,str类型;
margin_rate -- 保证金比例,float类型;


 
代码示例:
def initialize(context):
g.security = ["CU2112.XSGE", "IF2112.CCFX"]
set_universe(g.security)

def before_trading_start(context, data):
# 获取股票池代码合约信息
for security in g.security:
info = get_instruments(security)
log.info(info)

def handle_data(context, data):
pass

ptrade获取分时成交数据-LEVEL2数据逐笔数据

Ptrade李魔佛 发表了文章 • 0 个评论 • 1882 次浏览 • 2023-02-04 12:27 • 来自相关话题

在接口文档 http://ptradeapi.com/#get_tick_direction
中提供了获取分时成交的数据。
 
使用场景
该函数在交易模块可用

接口说明
该接口用于获取当日分时成交行情数据。

注意事项:

1、沪深市场都有分时成交数据;

2、分时成交数据需开通level2行情才有数据推送,否则无数据返回;
返回字段:
返回
返回一个OrderedDict对象,包含每只代码的分时成交行情数据。(OrderedDict([(),()...]))

返回结果字段介绍:

time_stamp: 时间戳毫秒级(str:numpy.int64);
hq_px: 价格(str:numpy.float64);
hq_px64: 价格(str:numpy.int64)(行情暂不支持,返回均为0);
business_amount: 成交数量(str:numpy.int64);
business_balance: 成交金额(str:numpy.int64);
business_count: 成交笔数(str:numpy.int64);
business_direction: 成交方向(0:卖,1:买,2:平盘)(str:numpy.int64);
amount: 持仓量(str:numpy.int64)(行情暂不支持,返回均为0);
start_index: 分笔关联的逐笔开始序号(str:numpy.int64)(行情暂不支持,返回均为0);
end_index: 分笔关联的逐笔结束序号(str:numpy.int64)(行情暂不支持,返回均为0);
示例代码:
def initialize(context):
g.security = '000001.SZ'
set_universe(g.security)

def handle_data(context, data):
#获取000001.SZ的分时成交数据
direction_data = get_tick_direction(g.security)
log.info(direction_data)
#获取指定股票列表分时成交数据
direction_data = get_tick_direction(['000002.SZ','000032.SZ'])
log.info(direction_data)
#获取成交量
business_amount = direction_data['000002.SZ']['business_amount']
log.info('分时成交的成交量为:%s' % business_amount)
不过在handle_bar中或者tick_data中,实际行情推送最快也要3s,所以拿到的level2的是切片数据,即使拿到很多数据,可是行情获取时间间隔还是3s, 无法做到和qmt那样的level2逐笔订阅驱动。还有level2数据需要收费。ptrade目前常用的几个券商都不支持level2的。
 
目前有万一免五的qmt ptrade量化交易接口的券商吗?
 

 
  查看全部
在接口文档 http://ptradeapi.com/#get_tick_direction
中提供了获取分时成交的数据。
 
使用场景
该函数在交易模块可用

接口说明
该接口用于获取当日分时成交行情数据。

注意事项:

1、沪深市场都有分时成交数据;

2、分时成交数据需开通level2行情才有数据推送,否则无数据返回;

返回字段:
返回
返回一个OrderedDict对象,包含每只代码的分时成交行情数据。(OrderedDict([(),()...]))

返回结果字段介绍:

time_stamp: 时间戳毫秒级(str:numpy.int64);
hq_px: 价格(str:numpy.float64);
hq_px64: 价格(str:numpy.int64)(行情暂不支持,返回均为0);
business_amount: 成交数量(str:numpy.int64);
business_balance: 成交金额(str:numpy.int64);
business_count: 成交笔数(str:numpy.int64);
business_direction: 成交方向(0:卖,1:买,2:平盘)(str:numpy.int64);
amount: 持仓量(str:numpy.int64)(行情暂不支持,返回均为0);
start_index: 分笔关联的逐笔开始序号(str:numpy.int64)(行情暂不支持,返回均为0);
end_index: 分笔关联的逐笔结束序号(str:numpy.int64)(行情暂不支持,返回均为0);

示例代码:
def initialize(context):
g.security = '000001.SZ'
set_universe(g.security)

def handle_data(context, data):
#获取000001.SZ的分时成交数据
direction_data = get_tick_direction(g.security)
log.info(direction_data)
#获取指定股票列表分时成交数据
direction_data = get_tick_direction(['000002.SZ','000032.SZ'])
log.info(direction_data)
#获取成交量
business_amount = direction_data['000002.SZ']['business_amount']
log.info('分时成交的成交量为:%s' % business_amount)

不过在handle_bar中或者tick_data中,实际行情推送最快也要3s,所以拿到的level2的是切片数据,即使拿到很多数据,可是行情获取时间间隔还是3s, 无法做到和qmt那样的level2逐笔订阅驱动。还有level2数据需要收费。ptrade目前常用的几个券商都不支持level2的。
 
目前有万一免五的qmt ptrade量化交易接口的券商吗?
 

 
 

ptrade移除当前ST股

Ptrade李魔佛 发表了文章 • 0 个评论 • 864 次浏览 • 2023-02-04 12:14 • 来自相关话题

 
下面代码移除创业板,科创板还有当前被ST的股票。也可以任意组合,移除。
可以参考上一篇:http://30daydo.com/article/44569
 
def remove_st_stock(all_stock_list):
st_dict = get_stock_status(all_stock_list, query_type='ST', query_date=None)
st_list = []
for k, v in st_dict.items():
if v:
st_list.append(k)
return st_list

MARKET_DICT = {0: '科创板', 1: '创业板', }
IGNORE_MARKET = [0, 1]

def all_codes_in_market():
all_stock_set = set(get_Ashares(date=None))
for ignore_code in IGNORE_MARKET:
market = MARKET_DICT.get(ignore_code)
if market == '科创板':
all_stock_set = all_stock_set - set(filter(lambda x: x.startswith('68'), all_stock_set))
if market == '创业板':
all_stock_set = all_stock_set - set(filter(lambda x: x.startswith('3'), all_stock_set))

return all_stock_set


def create_target(context):
all_stock_set = all_codes_in_market()
st_list = remove_st_stock(list(all_stock_set))
all_stock_set = all_stock_set - set(st_list)
return all_stock_set
调用方式:

stock_target = create_target(None)
 
这样返回的股票就被排除了科创板,创业板,ST股票。
 

 
  查看全部
 
下面代码移除创业板,科创板还有当前被ST的股票。也可以任意组合,移除。
可以参考上一篇:http://30daydo.com/article/44569
 
def remove_st_stock(all_stock_list):
st_dict = get_stock_status(all_stock_list, query_type='ST', query_date=None)
st_list = []
for k, v in st_dict.items():
if v:
st_list.append(k)
return st_list

MARKET_DICT = {0: '科创板', 1: '创业板', }
IGNORE_MARKET = [0, 1]

def all_codes_in_market():
all_stock_set = set(get_Ashares(date=None))
for ignore_code in IGNORE_MARKET:
market = MARKET_DICT.get(ignore_code)
if market == '科创板':
all_stock_set = all_stock_set - set(filter(lambda x: x.startswith('68'), all_stock_set))
if market == '创业板':
all_stock_set = all_stock_set - set(filter(lambda x: x.startswith('3'), all_stock_set))

return all_stock_set


def create_target(context):
all_stock_set = all_codes_in_market()
st_list = remove_st_stock(list(all_stock_set))
all_stock_set = all_stock_set - set(st_list)
return all_stock_set

调用方式:

stock_target = create_target(None)
 
这样返回的股票就被排除了科创板,创业板,ST股票。
 

 
 

ptrade排除A股创业板,科创板的股票

Ptrade李魔佛 发表了文章 • 0 个评论 • 992 次浏览 • 2023-02-04 10:48 • 来自相关话题

由于创业板和科创板的股票波动会比沪深主板的要大,所以如果想要按照某些策略,排除这两个板块的股票,可以使用下面的方法:
 
MARKET_DICT = {0: '科创板', 1: '创业板', }
IGNORE_MARKET = [0, 1]

def create_target(context):

all_stock_set = set(get_Ashares(date=None))
for ignore_code in IGNORE_MARKET:
market = MARKET_DICT.get(ignore_code)
if market == '科创板':
all_stock_set = all_stock_set - set(filter(lambda x:x.startswith('68'),all_stock_set))
if market == '创业板':
all_stock_set = all_stock_set - set(filter(lambda x:x.startswith('3'),all_stock_set))

return all_stock_set
返回的all_stock_set就是排除了创业板,科创板的股票列表。
 
ptrade接口文档:http://ptradeapi.com
  查看全部
由于创业板和科创板的股票波动会比沪深主板的要大,所以如果想要按照某些策略,排除这两个板块的股票,可以使用下面的方法:
 
MARKET_DICT = {0: '科创板', 1: '创业板', }
IGNORE_MARKET = [0, 1]

def create_target(context):

all_stock_set = set(get_Ashares(date=None))
for ignore_code in IGNORE_MARKET:
market = MARKET_DICT.get(ignore_code)
if market == '科创板':
all_stock_set = all_stock_set - set(filter(lambda x:x.startswith('68'),all_stock_set))
if market == '创业板':
all_stock_set = all_stock_set - set(filter(lambda x:x.startswith('3'),all_stock_set))

return all_stock_set

返回的all_stock_set就是排除了创业板,科创板的股票列表。
 
ptrade接口文档:http://ptradeapi.com
 

ptrade如何获取某天的全市场股票代码?

Ptrade李魔佛 发表了文章 • 0 个评论 • 1176 次浏览 • 2023-02-04 03:19 • 来自相关话题

ptrade如何获取全市场股票代码?
 
在ptrade的接口文档http://ptradeapi.com 里面可以查到,
 
get_Ashares – 获取指定日期A股代码列表
 
get_Ashares(date=None)

 
如果不指定日期,则获取单天的A股所有股票的股票代码。
 
如果在回测的时候,获取的是回测单天额所有股票代码; 如果指定日期,则获取的是指定日期的所有A股股票代码。

get_Ashares – 获取指定日期A股代码列表get_Ashares(date=None)使用场景

该函数在研究、回测、交易模块可用

接口说明

该接口用于获取指定日期沪深市场的所有A股代码列表

注意事项:

1、在回测中,date不入参默认取回测日期,默认值会随着回测日期变化而变化,等于context.current_dt

2、在研究中,date不入参默认取当天日期

3、在交易中,date不入参默认取当天日期

参数

date:格式为YYYYmmdd

返回

股票代码列表,list类型(list[str,...])

 
让我们来测试一下:





 
拿到的股票个数是4912个。
 
然后我对着通达信的所有A股数据比较了一下,get_Ashares 获取的数据不包括北交所,新三板创新创业的股票,也就是不包括4和8开头的股票数据,但包含沪深主板,创业板,科创板的股票数据。
 

  查看全部
ptrade如何获取全市场股票代码?
 
在ptrade的接口文档http://ptradeapi.com 里面可以查到,
 
get_Ashares – 获取指定日期A股代码列表
 
get_Ashares(date=None)

 
如果不指定日期,则获取单天的A股所有股票的股票代码。
 
如果在回测的时候,获取的是回测单天额所有股票代码; 如果指定日期,则获取的是指定日期的所有A股股票代码。


get_Ashares – 获取指定日期A股代码列表get_Ashares(date=None)使用场景

该函数在研究、回测、交易模块可用

接口说明

该接口用于获取指定日期沪深市场的所有A股代码列表

注意事项:

1、在回测中,date不入参默认取回测日期,默认值会随着回测日期变化而变化,等于context.current_dt

2、在研究中,date不入参默认取当天日期

3、在交易中,date不入参默认取当天日期

参数

date:格式为YYYYmmdd

返回

股票代码列表,list类型(list[str,...])


 
让我们来测试一下:

20230204002.jpg

 
拿到的股票个数是4912个。
 
然后我对着通达信的所有A股数据比较了一下,get_Ashares 获取的数据不包括北交所,新三板创新创业的股票,也就是不包括4和8开头的股票数据,但包含沪深主板,创业板,科创板的股票数据。
 

 

国信可以使用miniqmt吗?

QMT李魔佛 发表了文章 • 0 个评论 • 2534 次浏览 • 2023-01-21 15:52 • 来自相关话题

 之前群里有国信的小伙伴说,国信的mini qmt无法使用的。
 
所以笔者特意去问了下国信的好友兼营业部经理,但他回复说,个人只要申请,就可以开通mini qmt。如果不申请,是无法使用的,无法连接上去。
 
但因为开通这个是不用门槛的,可能会有部分不懂的或者不愿意的经理会和客户说不支持,或者需要机构这样话语。

具体情况,具体分析。


1. 国信证券iQuant策略交易平台精简版是指国信证券iQuant策略交易平台更专业快速且简洁的版本,满足股票、期货、期权、基金等全品种交易需求。
2. 风险等级:R4
 投资期限:0-1年
投资品种:权益类投资品种如股票、混合型基金、偏股型基金、股票型基金等。
3. 平台使用不收取费用。

 

 
具体的申请表如下:





 
不过申请了这个权限后,只能进行拉取数据,并没有交易权限。。交易权限需要机构才能开通。郁闷,看来国信的miniqmt是无法进行交易的了,只能白嫖点数据。

如果需要文字word版本,
可以到公众号后台回复:  国信mini申请 
获取word版本。

 

或者加微信开通指定的营业部的国信qmt(iquant), 也可以帮你开通mini qmt。

 
  查看全部

20230220003.jpg

 之前群里有国信的小伙伴说,国信的mini qmt无法使用的。
 
所以笔者特意去问了下国信的好友兼营业部经理,但他回复说,个人只要申请,就可以开通mini qmt。如果不申请,是无法使用的,无法连接上去。
 
但因为开通这个是不用门槛的,可能会有部分不懂的或者不愿意的经理会和客户说不支持,或者需要机构这样话语。

具体情况,具体分析。



1. 国信证券iQuant策略交易平台精简版是指国信证券iQuant策略交易平台更专业快速且简洁的版本,满足股票、期货、期权、基金等全品种交易需求。
2. 风险等级:R4
 投资期限:0-1年
投资品种:权益类投资品种如股票、混合型基金、偏股型基金、股票型基金等。
3. 平台使用不收取费用。

 


 
具体的申请表如下:

20230121154931708.png

 
不过申请了这个权限后,只能进行拉取数据,并没有交易权限。。交易权限需要机构才能开通。郁闷,看来国信的miniqmt是无法进行交易的了,只能白嫖点数据。

如果需要文字word版本,
可以到公众号后台回复:  国信mini申请 
获取word版本。

 

或者加微信开通指定的营业部的国信qmt(iquant), 也可以帮你开通mini qmt。

 
 

github首页Maximum retries exceeded Please add an env variable called PAT_1 with your token

网络马化云 发表了文章 • 0 个评论 • 1427 次浏览 • 2023-01-18 11:12 • 来自相关话题

最近登录github后,发现之前显示的状态都不正常了。
正常的时候是这样的:





但现在提示是这样的:






Something went wrong! file an issue at https://tiny.one/readme-statsMaximum retries exceeded Please add an env variable called PAT_1 with your github token in vercel

 
有两个办法可以解决。
1. Set it up yourself using Vercel (requires some step)
2. Use URL provided by others (The easiest step)
 
翻译成中文:
1. 自己到vercel上部署一个这样的app (复杂)
2. 换一个其他人部署好的链接 (容易)
 
一般人就别折腾第一种方法了,直接使用第二种方法就好了。
 
笔者找了一些其他人部署好的链接:
 
拿去用就可以了:https://github-readme-stats-git-masterrstaa-rickstaa.vercel.app
By Unknown

https://github-readme-stats-ruby-one.vercel.app
By Claudio Tancredi

https://github-readme-stats-ten-gilt.vercel.app
By Unknown

https://github-readme-stats-61 ... l.app
By Fanwang Meng

https://github-readme-stats.zohan.tech
By Zohan Subhash

https://readme-stats.clckblog.space
By Kevin Zhong

  查看全部
最近登录github后,发现之前显示的状态都不正常了。
正常的时候是这样的:

20230118001.jpg

但现在提示是这样的:

20230118002.jpg


Something went wrong! file an issue at https://tiny.one/readme-statsMaximum retries exceeded Please add an env variable called PAT_1 with your github token in vercel


 
有两个办法可以解决。
1. Set it up yourself using Vercel (requires some step)
2. Use URL provided by others (The easiest step)
 
翻译成中文:
1. 自己到vercel上部署一个这样的app (复杂)
2. 换一个其他人部署好的链接 (容易)
 
一般人就别折腾第一种方法了,直接使用第二种方法就好了。
 
笔者找了一些其他人部署好的链接:
 
拿去用就可以了:
https://github-readme-stats-git-masterrstaa-rickstaa.vercel.app
By Unknown

https://github-readme-stats-ruby-one.vercel.app
By Claudio Tancredi

https://github-readme-stats-ten-gilt.vercel.app
By Unknown

https://github-readme-stats-61 ... l.app
By Fanwang Meng

https://github-readme-stats.zohan.tech
By Zohan Subhash

https://readme-stats.clckblog.space
By Kevin Zhong


 

成为全栈工程师的技能与学习网站。(推特上推荐的)

每日总结马化云 发表了文章 • 0 个评论 • 673 次浏览 • 2023-01-17 16:06 • 来自相关话题

HTML [➡️] learn-html.org 
CSS [➡️] web.dev/learn/css 
JavaScript [➡️] javascript .info 
Git [➡️] atlassian.com/git 
React [➡️] beta.reactjs.org 
Node [➡️] nodejs.dev/en/learn 
Postgres [➡️] postgresqltutorial.com 
API [➡️] rapidapi.com/learn
 当然上面资料应该是英文的。当作练习练习英文吧。 查看全部
HTML [➡️] learn-html.org 
CSS [➡️] web.dev/learn/css 
JavaScript [➡️] javascript .info 
Git [➡️] atlassian.com/git 
React [➡️] beta.reactjs.org 
Node [➡️] nodejs.dev/en/learn 
Postgres [➡️] postgresqltutorial.com 
API [➡️] rapidapi.com/learn
 当然上面资料应该是英文的。当作练习练习英文吧。

目前有万一免五的qmt ptrade量化交易接口的券商吗?

券商万一免五李魔佛 发表了文章 • 0 个评论 • 3570 次浏览 • 2023-01-08 19:31 • 来自相关话题

==== 2023-02-03 更新 ======
目前量化qmt 有可以免五的券商了,国信,国元
 
国元证券万一免五,最低0元起步,免五门槛入金1w,不过开通qmt的门槛是100w
 
国信证券万一免五,门槛是100门槛,不过如果只是开通qmt(iquant),它的门槛是比较低的,入金2w就可以了
 
综合来看,如要要用qmt+万一免五,入金要100w的。
 目前(截至2023-01-08日) 市场上已经没有可以免五的支持qmt,ptrade的量化交易券商。 
当然动辄入金500w-5000W的券商就忽略了,大部分散户是达不到这个资金要求的。 
 
在正常条件下,入金1W 到 50W的范围内,目前多家券商已经停止股票免五了,费率最低是万一, 不过可以在开户后2-6月申请免五。【国金】 
 
或者先把户开了,把量化接口的权限也开了,等到券商可以重新申请免五的时候申请即可。 目前多家券商的营业部老板也承诺了,只要后续免五开放,就可以帮有量化交易权限的用户申请免五。
(最晚大概3月低可以免5)【国盛】




当然如果如果有券商营业部可以支持免五,也可以联系微信自荐,诚意合作。







 
 
  查看全部
==== 2023-02-03 更新 ======
目前量化qmt 有可以免五的券商了,国信,国元
 
国元证券万一免五,最低0元起步,免五门槛入金1w,不过开通qmt的门槛是100w
 
国信证券万一免五,门槛是100门槛,不过如果只是开通qmt(iquant),它的门槛是比较低的,入金2w就可以了
 
综合来看,如要要用qmt+万一免五,入金要100w的。
 目前(截至2023-01-08日) 市场上已经没有可以免五的支持qmt,ptrade的量化交易券商。 
当然动辄入金500w-5000W的券商就忽略了,大部分散户是达不到这个资金要求的。 
 
在正常条件下,入金1W 到 50W的范围内,目前多家券商已经停止股票免五了,费率最低是万一, 不过可以在开户后2-6月申请免五。【国金】 
 
或者先把户开了,把量化接口的权限也开了,等到券商可以重新申请免五的时候申请即可。 目前多家券商的营业部老板也承诺了,只要后续免五开放,就可以帮有量化交易权限的用户申请免五。
(最晚大概3月低可以免5)【国盛】
v2-d4f747d1d49a1121c68bee2d54a5a37a_r.jpg

当然如果如果有券商营业部可以支持免五,也可以联系微信自荐,诚意合作。

20230108002.jpg



 
 
 

ptrade生产环境在开盘交易时间无法回测,有什么办法可以解决?

Ptrade李魔佛 发表了文章 • 0 个评论 • 1338 次浏览 • 2023-01-06 12:07 • 来自相关话题

2023-01-06 10:41:46 Error: 回测运行失败, 错误码:2 错误信息: 当前时间不允许创建回测 





 在正式环境下,多个券商的ptrade都无法进行回测。
 
但也有办法解决。 就是使用ptrade的仿真客户端。 仿真客户端并连接实盘交易。所以没有这个时间的限制。
笔者在几个券商的上的仿真客户端都可以在交易时间使用回测功能。
可能部分仿真客户端需要申请才给开通的。
  查看全部


2023-01-06 10:41:46 Error: 回测运行失败, 错误码:2 错误信息: 当前时间不允许创建回测 


20230106002.jpg

 在正式环境下,多个券商的ptrade都无法进行回测。
 
但也有办法解决。 就是使用ptrade的仿真客户端。 仿真客户端并连接实盘交易。所以没有这个时间的限制。
笔者在几个券商的上的仿真客户端都可以在交易时间使用回测功能。
可能部分仿真客户端需要申请才给开通的。
 

ptrade回测结束后执行某个函数,比如保存回测结果

Ptrade李魔佛 发表了文章 • 0 个评论 • 843 次浏览 • 2023-01-01 17:56 • 来自相关话题

http://ptradeapi.com/#after_trading_end
官方文档只提供一个每天盘后执行的函数,没有函数可以在回测结束后,固定执行某些操作。
 
比如我回测过程保存的历史交易记录,收益率等,要如何保存? 虽然可以在回测的时候,每个交易日保存一次。
但是这样就需要在回测的时候按照天打开文件,盘后写入一次。 使用一个全局对象操作,显得很啰嗦。
 
那么有没有办法可以做在回测结束后一次性 保存操作呢?
 
答案是有的。也很简单。 适用于ptrade,qmt。
https://t.zsxq.com/09yigu5dy

 

 
  查看全部
http://ptradeapi.com/#after_trading_end
官方文档只提供一个每天盘后执行的函数,没有函数可以在回测结束后,固定执行某些操作。
 
比如我回测过程保存的历史交易记录,收益率等,要如何保存? 虽然可以在回测的时候,每个交易日保存一次。
但是这样就需要在回测的时候按照天打开文件,盘后写入一次。 使用一个全局对象操作,显得很啰嗦。
 
那么有没有办法可以做在回测结束后一次性 保存操作呢?
 
答案是有的。也很简单。 适用于ptrade,qmt。
https://t.zsxq.com/09yigu5dy

 

 
 

ptrade回测 获取回测当天的分时数据

Ptrade李魔佛 发表了文章 • 0 个评论 • 1090 次浏览 • 2023-01-01 15:45 • 来自相关话题

http://ptradeapi.com/#get_price
ptrade api的文档第3条表明,
 

3、数据返回内容不包括当天数据。

也就是用get_price是拿不到回测当天的数据。
 
比如下面的例子:
def initialize(context):
# 初始化策略
run_daily(context, execute, '09:36')

def handle_data(context, data):
pass


def execute(context):
current = context.blotter.current_dt.strftime('%Y-%m-%d')
log.info(current)
security='128025.SZ'
df = get_price(security, start_date=None, end_date=None, frequency='1m', fields=None, fq=None, count=10)
log.info(df)
返回的数据:
2023-01-01 15:31:21 开始运行回测, 策略名称: 四叶草-指定时间价格
2022-12-01 09:36:00 - INFO - 2022-12-01
2022-12-01 09:36:00 - INFO - open high low close volume \
2022-11-30 14:51:00 276.510 276.560 274.626 275.500 217510.0
2022-11-30 14:52:00 275.240 278.638 275.205 278.398 363820.0
2022-11-30 14:53:00 278.485 278.895 276.660 277.479 307570.0
2022-11-30 14:54:00 277.337 278.440 276.660 278.440 239370.0
2022-11-30 14:55:00 279.900 287.113 279.900 287.113 853170.0
2022-11-30 14:56:00 287.113 288.526 286.533 288.125 581860.0
2022-11-30 14:57:00 288.126 291.800 287.909 291.361 523580.0
2022-11-30 14:58:00 291.500 292.980 291.500 291.800 36480.0
2022-11-30 14:59:00 291.800 291.800 291.800 291.800 0.0
2022-11-30 15:00:00 292.510 292.510 292.510 292.510 421398.0
回测日期是2022-12-01日,每天09:36运行,那10根数据。
但返回的数据是昨天的收盘前的10根分时数据。并非当天9:36分开始拿10根bar。
 
如果把日期数据也固定,
df = get_price(security, start_date='2022-12-01', end_date=None, frequency='1m', fields=None, fq=None, count=10)

实际拿到的数据是空的,也就是无法拿到当天的数据。
 
正确的用法:
 
def initialize(context):
# 初始化策略
run_daily(context, execute, '09:36')

def handle_data(context, data):
pass


def execute(context):
current = context.blotter.current_dt.strftime('%Y-%m-%d')
log.info(current)
security='128025.SZ'
count=6
df=get_history(count, frequency='1m', field='close', security_list=security, fq=None, include=False, fill='nan')
log.info(df)

返回的数据:





 
欢迎关注公众号 查看全部
http://ptradeapi.com/#get_price
ptrade api的文档第3条表明,
 


3、数据返回内容不包括当天数据。


也就是用get_price是拿不到回测当天的数据。
 
比如下面的例子:
def initialize(context):
# 初始化策略
run_daily(context, execute, '09:36')

def handle_data(context, data):
pass


def execute(context):
current = context.blotter.current_dt.strftime('%Y-%m-%d')
log.info(current)
security='128025.SZ'
df = get_price(security, start_date=None, end_date=None, frequency='1m', fields=None, fq=None, count=10)
log.info(df)

返回的数据:
2023-01-01 15:31:21 开始运行回测, 策略名称: 四叶草-指定时间价格
2022-12-01 09:36:00 - INFO - 2022-12-01
2022-12-01 09:36:00 - INFO - open high low close volume \
2022-11-30 14:51:00 276.510 276.560 274.626 275.500 217510.0
2022-11-30 14:52:00 275.240 278.638 275.205 278.398 363820.0
2022-11-30 14:53:00 278.485 278.895 276.660 277.479 307570.0
2022-11-30 14:54:00 277.337 278.440 276.660 278.440 239370.0
2022-11-30 14:55:00 279.900 287.113 279.900 287.113 853170.0
2022-11-30 14:56:00 287.113 288.526 286.533 288.125 581860.0
2022-11-30 14:57:00 288.126 291.800 287.909 291.361 523580.0
2022-11-30 14:58:00 291.500 292.980 291.500 291.800 36480.0
2022-11-30 14:59:00 291.800 291.800 291.800 291.800 0.0
2022-11-30 15:00:00 292.510 292.510 292.510 292.510 421398.0

回测日期是2022-12-01日,每天09:36运行,那10根数据。
但返回的数据是昨天的收盘前的10根分时数据。并非当天9:36分开始拿10根bar。
 
如果把日期数据也固定,
    df = get_price(security, start_date='2022-12-01', end_date=None, frequency='1m', fields=None, fq=None, count=10)

实际拿到的数据是空的,也就是无法拿到当天的数据。
 
正确的用法:
 
def initialize(context):
# 初始化策略
run_daily(context, execute, '09:36')

def handle_data(context, data):
pass


def execute(context):
current = context.blotter.current_dt.strftime('%Y-%m-%d')
log.info(current)
security='128025.SZ'
count=6
df=get_history(count, frequency='1m', field='close', security_list=security, fq=None, include=False, fill='nan')
log.info(df)

返回的数据:

20230101154423810.png

 
欢迎关注公众号

Ptrade获取可转债强赎数据

Ptrade李魔佛 发表了文章 • 0 个评论 • 1276 次浏览 • 2022-12-21 15:50 • 来自相关话题

对于强赎的可转债而言,期权价值归0,叠加一个转股压力。类似于股票解禁的效果,导致转债和正股一起下跌。





 
所以在可转债的策略里面,把强赎的转债排除掉,是一个不错的因子。
 
但内置的ptrade接口数据并无提供任何转债相关的数据。
 
不过笔者这里提供了一个自研的数据接口。
 
http://ptradeapi.com/#%E5%8F%AF%E8%BD%AC%E5%80%BA%E5%BC%BA%E8%B5%8E%E4%B8%8E%E6%95%B0%E6%97%A5%E5%AD%90
 
方便在ptrade里面调用。
  查看全部
对于强赎的可转债而言,期权价值归0,叠加一个转股压力。类似于股票解禁的效果,导致转债和正股一起下跌。

haerzuanzai.jpeg

 
所以在可转债的策略里面,把强赎的转债排除掉,是一个不错的因子。
 
但内置的ptrade接口数据并无提供任何转债相关的数据。
 
不过笔者这里提供了一个自研的数据接口。
 
http://ptradeapi.com/#%E5%8F%AF%E8%BD%AC%E5%80%BA%E5%BC%BA%E8%B5%8E%E4%B8%8E%E6%95%B0%E6%97%A5%E5%AD%90
 
方便在ptrade里面调用。
 

20221221003.jpg

Ptrade API 文档

Ptrade李魔佛 发表了文章 • 0 个评论 • 1544 次浏览 • 2022-12-18 20:18 • 来自相关话题

部署一个ptrade APi文档的小站,便于平时做量化的朋友查询。
 
http://ptradeapi.com/





 





 
以后再也不用在ptrade的编辑页面与编辑页面来回切换了。 查看全部
部署一个ptrade APi文档的小站,便于平时做量化的朋友查询。
 
http://ptradeapi.com/

20221218005.jpg

 

20221218006.jpg

 
以后再也不用在ptrade的编辑页面与编辑页面来回切换了。

ubuntu snap 配置不更新新软件

Linux马化云 发表了文章 • 0 个评论 • 930 次浏览 • 2022-12-17 14:20 • 来自相关话题

它默认会自动更新软件,非常的烦。
 
网上的禁用方法
$ snap refresh --hold
error: unknown flag `hold'
在ubuntu20.04上是没有用的。因为它的snap不是最新的。要在ubuntu22.04上才可以。
 
在ubuntu 20.04上,
 
$ sudo snap set system refresh.hold="2030-01-01T01:00:00-01:00"
$ sudo snap set system refresh.metered=hold
网上说 snap最多只能设置60天内不更新,所以还需要配合crontab,在计划任务里面设置时间。
 
  查看全部
它默认会自动更新软件,非常的烦。
 
网上的禁用方法
$ snap refresh --hold
error: unknown flag `hold'

在ubuntu20.04上是没有用的。因为它的snap不是最新的。要在ubuntu22.04上才可以。
 
在ubuntu 20.04上,
 
$ sudo snap set system refresh.hold="2030-01-01T01:00:00-01:00"
$ sudo snap set system refresh.metered=hold

网上说 snap最多只能设置60天内不更新,所以还需要配合crontab,在计划任务里面设置时间。
 
 

pycharm 最新版2022.03 无法使用ida-eval-resetter 插件重置试用日期

python马化云 发表了文章 • 0 个评论 • 2432 次浏览 • 2022-12-17 14:10 • 来自相关话题

 
0x5. 新试用机制

最新的IDE试用需要登录,我们可以任选以下方式中的一种来继续使用重置插件:

使用网络上热心大佬收集总结的key,进入IDE后使用重置插件。
登录账号试用IDE,安装设置好本插件,退出登录账号重启IDE即可。
先安装旧版本IDE,安装设置好本插件,升级IDE到最新版本即可。

不管哪种方法原理都是为了让你进入IDE,以便重置插件接管试用。
2021.3已经彻底不支持离线试用,本重置插件已失效。可以考虑暂缓升级至2021.3!
 






如果要使用重置日期插件,那么得要把你的pycharm降级到2021.3版本或者以下。
  查看全部
 
0x5. 新试用机制

最新的IDE试用需要登录,我们可以任选以下方式中的一种来继续使用重置插件:

使用网络上热心大佬收集总结的key,进入IDE后使用重置插件。
登录账号试用IDE,安装设置好本插件,退出登录账号重启IDE即可。
先安装旧版本IDE,安装设置好本插件,升级IDE到最新版本即可。

不管哪种方法原理都是为了让你进入IDE,以便重置插件接管试用。
2021.3已经彻底不支持离线试用,本重置插件已失效。可以考虑暂缓升级至2021.3!
 

20221217001.jpg


如果要使用重置日期插件,那么得要把你的pycharm降级到2021.3版本或者以下。
 

ubuntu snap 下载指定版本的pycharm goland

Linux李魔佛 发表了文章 • 0 个评论 • 1337 次浏览 • 2022-12-17 13:24 • 来自相关话题

之前用的pycharm,goland被snap自动更新,更新到2022.3 , 导致之前的ida-eval-resetter 无法使用。
 
所以只好回滚到指定的pycharm版本。
 
使用snap可以下载指定版本的pycharm和goland
 sudo snap install pycharm-professional --channel=2021.2/stable --classic 
上面的命令下载  2021.2/stable的版本的pycharm
 
那么怎么查看pycharm的版本?snap info pycharm-professionalname: pycharm-professional
summary: PyCharm Professional Edition
publisher: jetbrains✓
store-url: https://snapcraft.io/pycharm-professional
contact: https://www.jetbrains.com/pycharm/documentation/
license: unset
description: |
Python IDE for professional developers. Save time while PyCharm takes care of the r
on bigger things and embrace the keyboard-centric approach to get the most of PyCha
productivity features.
commands:
- pycharm-professional
snap-id: Uqpw0ZWqy6Wh4mgaWE0rxgM5tAGCwf4D
tracking: latest/stable
refresh-date: 15 days ago, at 09:57 CST
channels:
latest/stable: 2022.3 2022-12-01 (314) 779MB classic
latest/candidate: 2022.3.1-RC 2022-12-12 (315) 793MB classic
latest/beta: 2022.3.1-RC 2022-12-12 (315) 793MB classic
latest/edge: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.3/stable: 2022.3 2022-12-01 (314) 779MB classic
2022.3/candidate: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.3/beta: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.3/edge: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.2/stable: 2022.2.4 2022-11-17 (311) 764MB classic
2022.2/candidate: 2022.2.4 2022-11-17 (311) 764MB classic
2022.2/beta: 2022.2.4 2022-11-17 (311) 764MB classic
2022.2/edge: 2022.2.4 2022-11-17 (311) 764MB classic
2022.1/stable: 2022.1.4 2022-07-21 (295) 759MB classic
2022.1/candidate: 2022.1.4 2022-07-21 (295) 759MB classic
2022.1/beta: 2022.1.4 2022-07-21 (295) 759MB classic
2022.1/edge: 2022.1.4 2022-07-21 (295) 759MB classic
2021.3/stable: 2021.3.3 2022-03-17 (278) 702MB classic
2021.3/candidate: 2021.3.3 2022-03-17 (278) 702MB classic
2021.3/beta: 2021.3.3 2022-03-17 (278) 702MB classic
2021.3/edge: 2021.3.3 2022-03-17 (278) 702MB classic
2021.2/stable: 2021.2.4 2021-12-22 (268) 565MB classic
2021.2/candidate: 2021.2.4 2021-12-22 (268) 565MB classic
2021.2/beta: 2021.2.4 2021-12-22 (268) 565MB classic
2021.2/edge: 2021.2.4 2021-12-22 (268) 565MB classic
2021.1/stable: 2021.1.3 2021-06-30 (248) 530MB classic
2021.1/candidate: 2021.1.3 2021-06-30 (248) 530MB classic
2021.1/beta: 2021.1.3 2021-06-30 (248) 530MB classic
2021.1/edge: 2021.1.3 2021-06-30 (248) 530MB classic
2020.3/stable: 2020.3.5 2021-03-26 (237) 559MB classic
2020.3/candidate: 2020.3.5 2021-03-26 (237) 559MB classic
2020.3/beta: 2020.3.5 2021-03-26 (237) 559MB classic
2020.3/edge: 2020.3.5 2021-03-26 (237) 559MB classic
2020.2/stable: 2020.2.5 2020-12-02 (225) 479MB classic
2020.2/candidate: 2020.2.5 2020-12-02 (225) 479MB classic
2020.2/beta: 2020.2.5 2020-12-02 (225) 479MB classic
2020.2/edge: 2020.2.5 2020-12-02 (225) 479MB classic
2020.1/stable: 2020.1.5 2020-12-02 (224) 465MB classic
2020.1/candidate: 2020.1.5 2020-12-02 (224) 465MB classic
2020.1/beta: 2020.1.5 2020-12-02 (224) 465MB classic
2020.1/edge: 2020.1.5 2020-12-02 (224) 465MB classic
2019.3/stable: 2019.3.5 2020-05-08 (199) 473MB classic
2019.3/candidate: ↑
2019.3/beta: ↑
2019.3/edge: ↑
2019.2/stable: 2019.2.6 2020-02-10 (184) 445MB classic
2019.2/candidate: ↑
2019.2/beta: ↑
2019.2/edge: ↑
2019.1/stable: 2019.1.4 2019-07-30 (148) 394MB classic
2019.1/candidate: ↑
2019.1/beta: ↑
2019.1/edge: ↑
2018.3/stable: 2018.3.7 2019-07-10 (142) 355MB classic
2018.3/candidate: ↑
2018.3/beta: ↑
2018.3/edge: ↑
2018.2/stable: 2018.2.8 2019-04-12 (128) 313MB classic
2018.2/candidate: ↑
2018.2/beta: ↑
2018.2/edge: ↑
2018.1/stable: 2018.1.6 2018-11-15 (101) 314MB classic
2018.1/candidate: ↑
2018.1/beta: ↑
2018.1/edge: ↑
2017.3/stable: 2017.3.7 2018-11-15 (100) 344MB classic
2017.3/candidate: ↑
2017.3/beta: ↑
2017.3/edge: ↑
installed: 2022.3 (314) 779MB classic
只要在里面挑一个好一点的版本就好了。
 
  查看全部
之前用的pycharm,goland被snap自动更新,更新到2022.3 , 导致之前的ida-eval-resetter 无法使用。
 
所以只好回滚到指定的pycharm版本。
 
使用snap可以下载指定版本的pycharm和goland
 
sudo snap install pycharm-professional --channel=2021.2/stable --classic
 
上面的命令下载  2021.2/stable的版本的pycharm
 
那么怎么查看pycharm的版本?
snap info pycharm-professional
name:      pycharm-professional
summary: PyCharm Professional Edition
publisher: jetbrains✓
store-url: https://snapcraft.io/pycharm-professional
contact: https://www.jetbrains.com/pycharm/documentation/
license: unset
description: |
Python IDE for professional developers. Save time while PyCharm takes care of the r
on bigger things and embrace the keyboard-centric approach to get the most of PyCha
productivity features.
commands:
- pycharm-professional
snap-id: Uqpw0ZWqy6Wh4mgaWE0rxgM5tAGCwf4D
tracking: latest/stable
refresh-date: 15 days ago, at 09:57 CST
channels:
latest/stable: 2022.3 2022-12-01 (314) 779MB classic
latest/candidate: 2022.3.1-RC 2022-12-12 (315) 793MB classic
latest/beta: 2022.3.1-RC 2022-12-12 (315) 793MB classic
latest/edge: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.3/stable: 2022.3 2022-12-01 (314) 779MB classic
2022.3/candidate: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.3/beta: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.3/edge: 2022.3.1-RC 2022-12-12 (315) 793MB classic
2022.2/stable: 2022.2.4 2022-11-17 (311) 764MB classic
2022.2/candidate: 2022.2.4 2022-11-17 (311) 764MB classic
2022.2/beta: 2022.2.4 2022-11-17 (311) 764MB classic
2022.2/edge: 2022.2.4 2022-11-17 (311) 764MB classic
2022.1/stable: 2022.1.4 2022-07-21 (295) 759MB classic
2022.1/candidate: 2022.1.4 2022-07-21 (295) 759MB classic
2022.1/beta: 2022.1.4 2022-07-21 (295) 759MB classic
2022.1/edge: 2022.1.4 2022-07-21 (295) 759MB classic
2021.3/stable: 2021.3.3 2022-03-17 (278) 702MB classic
2021.3/candidate: 2021.3.3 2022-03-17 (278) 702MB classic
2021.3/beta: 2021.3.3 2022-03-17 (278) 702MB classic
2021.3/edge: 2021.3.3 2022-03-17 (278) 702MB classic
2021.2/stable: 2021.2.4 2021-12-22 (268) 565MB classic
2021.2/candidate: 2021.2.4 2021-12-22 (268) 565MB classic
2021.2/beta: 2021.2.4 2021-12-22 (268) 565MB classic
2021.2/edge: 2021.2.4 2021-12-22 (268) 565MB classic
2021.1/stable: 2021.1.3 2021-06-30 (248) 530MB classic
2021.1/candidate: 2021.1.3 2021-06-30 (248) 530MB classic
2021.1/beta: 2021.1.3 2021-06-30 (248) 530MB classic
2021.1/edge: 2021.1.3 2021-06-30 (248) 530MB classic
2020.3/stable: 2020.3.5 2021-03-26 (237) 559MB classic
2020.3/candidate: 2020.3.5 2021-03-26 (237) 559MB classic
2020.3/beta: 2020.3.5 2021-03-26 (237) 559MB classic
2020.3/edge: 2020.3.5 2021-03-26 (237) 559MB classic
2020.2/stable: 2020.2.5 2020-12-02 (225) 479MB classic
2020.2/candidate: 2020.2.5 2020-12-02 (225) 479MB classic
2020.2/beta: 2020.2.5 2020-12-02 (225) 479MB classic
2020.2/edge: 2020.2.5 2020-12-02 (225) 479MB classic
2020.1/stable: 2020.1.5 2020-12-02 (224) 465MB classic
2020.1/candidate: 2020.1.5 2020-12-02 (224) 465MB classic
2020.1/beta: 2020.1.5 2020-12-02 (224) 465MB classic
2020.1/edge: 2020.1.5 2020-12-02 (224) 465MB classic
2019.3/stable: 2019.3.5 2020-05-08 (199) 473MB classic
2019.3/candidate: ↑
2019.3/beta: ↑
2019.3/edge: ↑
2019.2/stable: 2019.2.6 2020-02-10 (184) 445MB classic
2019.2/candidate: ↑
2019.2/beta: ↑
2019.2/edge: ↑
2019.1/stable: 2019.1.4 2019-07-30 (148) 394MB classic
2019.1/candidate: ↑
2019.1/beta: ↑
2019.1/edge: ↑
2018.3/stable: 2018.3.7 2019-07-10 (142) 355MB classic
2018.3/candidate: ↑
2018.3/beta: ↑
2018.3/edge: ↑
2018.2/stable: 2018.2.8 2019-04-12 (128) 313MB classic
2018.2/candidate: ↑
2018.2/beta: ↑
2018.2/edge: ↑
2018.1/stable: 2018.1.6 2018-11-15 (101) 314MB classic
2018.1/candidate: ↑
2018.1/beta: ↑
2018.1/edge: ↑
2017.3/stable: 2017.3.7 2018-11-15 (100) 344MB classic
2017.3/candidate: ↑
2017.3/beta: ↑
2017.3/edge: ↑
installed: 2022.3 (314) 779MB classic

只要在里面挑一个好一点的版本就好了。
 
 

golang mysql count(*) 的写法

Golang马化云 发表了文章 • 0 个评论 • 1216 次浏览 • 2022-12-15 22:17 • 来自相关话题

mysql最为常用的语句。
 
使用golang标准库 database/sql 实现:
 
 
package main

import (
"database/sql"
"fmt"
"log"

_ "github.com/lib/pq"
)

func main() {
var count int

db, err := sql.Open("postgres", "user=test password=test dbname=foo sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()

row := db.QueryRow("SELECT COUNT(*) FROM table_name")
err := row.Scan(&count)
if err != nil {
log.Fatal(err)
}

fmt.Println(count)

即可。
 
  查看全部
mysql最为常用的语句。
 
使用golang标准库 database/sql 实现:
 
 
package main

import (
"database/sql"
"fmt"
"log"

_ "github.com/lib/pq"
)

func main() {
var count int

db, err := sql.Open("postgres", "user=test password=test dbname=foo sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()

row := db.QueryRow("SELECT COUNT(*) FROM table_name")
err := row.Scan(&count)
if err != nil {
log.Fatal(err)
}

fmt.Println(count)
}
 
即可。
 
 

golang mysql包 database/sql的基本操作:增删改查 (go sql操作 保存这篇文章就足够了)

Golang马化云 发表了文章 • 0 个评论 • 1255 次浏览 • 2022-12-15 12:06 • 来自相关话题

如果不是使用gorm,直接操作底层mysql命令,那么最常使用的是 database/sql 这个包了。

下面的是一些常见的操作,如果需要写底层sql语句,使用频率极高,值得收藏。
 /*
* @Author: 30daydo
* @FilePath: /go110/go-012/g012.go
* @Description: Go 数据库基本操作
*/

package main

import (
"database/sql"
"fmt"
"runtime"

_ "github.com/go-sql-driver/mysql"
)

/**
// 创建 user 表
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户信息表'
**/

// 全局对象 db
var db *sql.DB

// 定义一个 user 结构体接收数据:
type user struct {
id int
age int
name string
}

// 始化数据库的函数
func initDB() (err error) {

// 构建连接的 dsn 格式是:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
dsn := "user:password@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"

// 给全局变量赋值, 注意这里不要使用 :=
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Println("初始化数据库失败")
return err
}

// 校验dsn是否正确
fmt.Println("尝试与数据库建立连接...")
err = db.Ping()
if err != nil {
fmt.Println("连接失败")
return err
}
fmt.Println("连接成功")

db.SetMaxOpenConns(2000) // 设置最大打开连接数
db.SetMaxIdleConns(10) // 设置最大空闲连接数

return nil
}

// 插入数据
func insertRow(name string, age int) int64 {

sqlStr := "INSERT INTO user(name, age) VALUES (?,?)"

ret, err := db.Exec(sqlStr, name, age)

if err != nil {
fmt.Printf("插入失败, err: %v\n", err)
return 0
}

// 新插入数据的 id
insertId, err := ret.LastInsertId()
if err != nil {
fmt.Printf("获取新插入数据的 ID 失败, err:%v\n", err)
return 0
}
fmt.Printf("插入成功, ID 为 %d.\n", insertId)

return insertId
}

// 查询单条数据记录
func queryRow(rowId int64) {
sqlStr := "SELECT id, name, age FROM user WHERE id = ?"
var u user
// 确保 QueryRow 之后调用 Scan 方法,释放持有的数据库链接
err := db.QueryRow(sqlStr, rowId).Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("未找到记录, 查询失败, err: %v\n", err)
return
}
fmt.Printf("查询数据成功, id: %d name: %s age: %d \n", u.id, u.name, u.age)
}

// 更新数据
func updateRow(rowId int64, newAge int) {
sqlStr := "UPDATE user SET age=? WHERE id = ?"
ret, err := db.Exec(sqlStr, newAge, rowId)
if err != nil {
fmt.Printf("更新失败 , err:%v\n", err)
return
}
// 操作影响的行数
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("更新成功, 影响行数为: %d\n", n)
}

// 删除数据
func deleteRow(rowId int64) {
sqlStr := "DELETE FROM user WHERE id = ?"
ret, err := db.Exec(sqlStr, rowId)
if err != nil {
fmt.Printf("删除失败, err: %v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("删除成功, 影响行数为: %d\n", n)
}

// 查询多行
func queryMultiRow() {
sqlStr := "SELECT id, name, age FROM user WHERE id > ?"
rows, err := db.Query(sqlStr, 0)
if err != nil {
fmt.Printf("查询失败, err:%v\n", err)
return
}
// 重要:关闭 rows, 释放持有的数据库链接
defer rows.Close()

// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("查询多行数据失败, err:%v\n", err)
return
}
fmt.Printf("当前数据 id: %d name: %s age: %d\n", u.id, u.name, u.age)
}
}

func main() {
// 使用内置函数打印
println("Hello", "菜鸟实战")

// 初始化数据库
initDB()

// 插入数据
var id1 = insertRow("唐遇春", 17)
var id2 = insertRow("冯显", 38)
var id3 = insertRow("花千里", 20)

// 查询多行数据
queryMultiRow()

// 更新数据
updateRow(id2, 35)

// 查询单行数据
queryRow(id2)

// 删除数据
deleteRow(id1)

// 查询多行数据
queryMultiRow()
queryRow(id3)

// 当前版本
fmt.Printf("版本: %s \n", runtime.Version())
}
 
当然,上面的语句也可以不用Prepare的写法,直接插入进去:
 
func insertDirect() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "INSERT INTO user(id, name, pwd) VALUES(?, ?, ?)"
res, err := db.Exec(sql, 13, "Jobs", "444555")
checkErr(err)
fmt.Println(res.LastInsertId())

} 查看全部
如果不是使用gorm,直接操作底层mysql命令,那么最常使用的是 database/sql 这个包了。

下面的是一些常见的操作,如果需要写底层sql语句,使用频率极高,值得收藏。
 
/*
* @Author: 30daydo
* @FilePath: /go110/go-012/g012.go
* @Description: Go 数据库基本操作
*/

package main

import (
"database/sql"
"fmt"
"runtime"

_ "github.com/go-sql-driver/mysql"
)

/**
// 创建 user 表
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户信息表'
**/

// 全局对象 db
var db *sql.DB

// 定义一个 user 结构体接收数据:
type user struct {
id int
age int
name string
}

// 始化数据库的函数
func initDB() (err error) {

// 构建连接的 dsn 格式是:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
dsn := "user:password@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"

// 给全局变量赋值, 注意这里不要使用 :=
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Println("初始化数据库失败")
return err
}

// 校验dsn是否正确
fmt.Println("尝试与数据库建立连接...")
err = db.Ping()
if err != nil {
fmt.Println("连接失败")
return err
}
fmt.Println("连接成功")

db.SetMaxOpenConns(2000) // 设置最大打开连接数
db.SetMaxIdleConns(10) // 设置最大空闲连接数

return nil
}

// 插入数据
func insertRow(name string, age int) int64 {

sqlStr := "INSERT INTO user(name, age) VALUES (?,?)"

ret, err := db.Exec(sqlStr, name, age)

if err != nil {
fmt.Printf("插入失败, err: %v\n", err)
return 0
}

// 新插入数据的 id
insertId, err := ret.LastInsertId()
if err != nil {
fmt.Printf("获取新插入数据的 ID 失败, err:%v\n", err)
return 0
}
fmt.Printf("插入成功, ID 为 %d.\n", insertId)

return insertId
}

// 查询单条数据记录
func queryRow(rowId int64) {
sqlStr := "SELECT id, name, age FROM user WHERE id = ?"
var u user
// 确保 QueryRow 之后调用 Scan 方法,释放持有的数据库链接
err := db.QueryRow(sqlStr, rowId).Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("未找到记录, 查询失败, err: %v\n", err)
return
}
fmt.Printf("查询数据成功, id: %d name: %s age: %d \n", u.id, u.name, u.age)
}

// 更新数据
func updateRow(rowId int64, newAge int) {
sqlStr := "UPDATE user SET age=? WHERE id = ?"
ret, err := db.Exec(sqlStr, newAge, rowId)
if err != nil {
fmt.Printf("更新失败 , err:%v\n", err)
return
}
// 操作影响的行数
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("更新成功, 影响行数为: %d\n", n)
}

// 删除数据
func deleteRow(rowId int64) {
sqlStr := "DELETE FROM user WHERE id = ?"
ret, err := db.Exec(sqlStr, rowId)
if err != nil {
fmt.Printf("删除失败, err: %v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("删除成功, 影响行数为: %d\n", n)
}

// 查询多行
func queryMultiRow() {
sqlStr := "SELECT id, name, age FROM user WHERE id > ?"
rows, err := db.Query(sqlStr, 0)
if err != nil {
fmt.Printf("查询失败, err:%v\n", err)
return
}
// 重要:关闭 rows, 释放持有的数据库链接
defer rows.Close()

// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("查询多行数据失败, err:%v\n", err)
return
}
fmt.Printf("当前数据 id: %d name: %s age: %d\n", u.id, u.name, u.age)
}
}

func main() {
// 使用内置函数打印
println("Hello", "菜鸟实战")

// 初始化数据库
initDB()

// 插入数据
var id1 = insertRow("唐遇春", 17)
var id2 = insertRow("冯显", 38)
var id3 = insertRow("花千里", 20)

// 查询多行数据
queryMultiRow()

// 更新数据
updateRow(id2, 35)

// 查询单行数据
queryRow(id2)

// 删除数据
deleteRow(id1)

// 查询多行数据
queryMultiRow()
queryRow(id3)

// 当前版本
fmt.Printf("版本: %s \n", runtime.Version())
}

 
当然,上面的语句也可以不用Prepare的写法,直接插入进去:
 
func insertDirect() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "INSERT INTO user(id, name, pwd) VALUES(?, ?, ?)"
res, err := db.Exec(sql, 13, "Jobs", "444555")
checkErr(err)
fmt.Println(res.LastInsertId())

}