右键菜单

void CChildView::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
if (point.x == -1 && point.y == -1)
{
//keystroke invocation
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);

point = rect.TopLeft();
point.Offset(5, 5);
}

CMenu menu;
VERIFY(menu.LoadMenu(IDR_RMENU));

CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;

while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();

pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
pWndPopupOwner);
}

显示,隐藏菜单

// hide
this->SetMenu(NULL);
this->DrawMenuBar();

// show
CMenu m_Menu;
m_Menu.LoadMenuW(IDR_MENU1);
SetMenu(&m_Menu);
this->DrawMenuBar();

修改系统菜单

已经有代码了,直接添加自定义菜单就可以了。
需要在 Resource.h 里面手动添加一个菜单 ID #define IDM_SYSCOMMAND_CUSTOM 32771
别忘了修改一下下面的下一个可用 id 序号,

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 135
#define _APS_NEXT_COMMAND_VALUE 32772
#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 104
#endif
#endif
BOOL CMRLGaugerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
...

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
// 设置系统菜单
// 设置系统菜单 第一个参数可以设置选中,未选中 MF_UNCHECKED
// m_pSysMenu->AppendMenu(MF_CHECKED, IDM_SYSCOMMAND_CUSTOM, _T("Custom Menu"));
// pSysMenu->AppendMenu(0, IDM_SYSCOMMAND_CUSTOM, _T("Custom Menu"));
pSysMenu->InsertMenuW(0,MF_CHECKED| MF_BYPOSITION, IDM_SYSCOMMAND_CUSTOM, _T("菜单栏"));

}
...


void CMRLGaugerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}else if (nID == IDM_SYSCOMMAND_CUSTOM)
{
// toggle menu
if (MF_CHECKED == m_pSysMenu->GetMenuState(IDM_SYSCOMMAND_CUSTOM,MF_BYCOMMAND))
{
m_pSysMenu->CheckMenuItem(IDM_SYSCOMMAND_CUSTOM, MF_UNCHECKED);
}
else
{
m_pSysMenu->CheckMenuItem(IDM_SYSCOMMAND_CUSTOM, MF_CHECKED);
}

}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}

参考网页。
https://www.guru99.com/sqlite-query.html#4

limit,offset

跳过前 4 行,最多返回 3 行

SELECT * FROM Students LIMIT 4,3;

选出最新的一行

SELECT * FROM COMPANY ORDER BY NAME DESC limit 1;

选择非空的行

select f_ui_id,f_param from t_user where f_param is not null and f_param !=''

选择日期

select * from table1 where t1>='2017-06-01' and t1<='2017-06-05'

累加

SELECT sum(Amount) FROM "Model_trade_info" WHERE code=12312

REST:无状态的数据传输结构,适用于通用、快速迭代和标准化语义的场景。
gRPC:轻量的传输方式,特殊适合对性能高要求或者环境苛刻的场景,比如 IOT。
GraphQL: 请求者可以自定义返回格式,某些程度上可以减少前后端联调成本。
Webhooks: 推送服务,主要用于服务器主动更新客户端资源的场景。

nanomsg

website

zmq作者重新设计的一个框架,解决了一些zmq的问题。

作者的博客
http://250bpm.com/

go 实现

github

https://bravenewgeek.com/fast-scalable-networking-in-go-with-mangos/

scalability protocols are currently available

  • PAIR - simple one-to-one communication
  • BUS - simple many-to-many communication
  • REQREP - allows to build clusters of stateless services to process user requests
  • PUBSUB - distributes messages to large sets of interested subscribers
  • PIPELINE - aggregates messages from multiple sources and load balances them among many destinations
  • SURVEY - allows to query state of multiple applications in a single go

transports mechanisms

  • INPROC - transport within a process (between threads, modules etc.)
  • IPC - transport between processes on a single machine
  • TCP - network transport via TCP
  • WS - websockets over TCP

gRPC

The grpc library uses HTTP2 as a transport layer and provides a code generator based on the protocol buffer syntax making it very simple to use.

GraphQL

GraphQL 不是 REST 的替代品,而是另一种交互形式:前端决定后端的返回结果。

GraphQL 带来的最大好处是精简请求响应内容,不会出现冗余字段,前端可以决定后端返回什么数据。但要注意的是,前端的决定权取决于后端支持什么数据,因此 GraphQL 更像是精简了返回值的 REST,而后端接口也可以一次性定义完所有功能,而不需要逐个开发。

GraphQL 需要配套
GraphQL 不是 REST 的替代品,所以不要想着团队从 Http 接口迁移到 GraphQL 就能提升 X% 的开发效率。GraphQL 方案是一种新的前后端交互约定,所以上手成本会比较高,同时,为了方便前端同学拼 query,等于把一部分后端工作量转移给了前端,如果此时没有一个足够好用的平台快速查阅、生成、维护这些定义,开发效率可能不升反降。

总的来说,对外开放 API 或者拥有完整配套的场景,使用 GraphQL 是比较理想的,但对于快速迭代,平台又不够成熟的团队,继续使用标准 Http 接口可以更快完成项目。

Protocol Buffers vs json

优点:

  • 資料輕量化:資料非常輕量,省去了不必要的 { 或 : 累贅。
  • 混淆性:在一般人眼中無法輕易地猜測出資料結構為何,因為有經過編碼。
  • 效能高:處理速度很快。
  • 極具方便性:結構就是你的資料模型,你能夠直接在程式中使用這些結構,而不用建立新的物件來接納、映射(Mapping)這些資料。
  • 清晰明瞭、無需文件:.proto 檔案本身就是你的文件,不需要額外撰寫 API 或結構文件來告訴別人你接受怎樣的資料。

适合使用 json 的场景:

  • 當你希望資料是人類可解讀的時候。
  • 你不打算直接把接收到的資料拿來處理,你希望從中拿取部分資料作為處理。
  • 你希望在純文字、終端機的情況下就能夠與伺服器溝通。
  • 不想經過任何特殊處理,想直接在瀏覽器中解讀。

unable to open database file

sqlite数据库进行写操作时,会先生成缓存文件,对缓存进行操作
生成的缓存文件的读写权限默认和父目录相同

// 修改项目权限
chmod 777 /usr/share/nginx/html
// 修改数据文件权限
chmod 777 /usr/share/nginx/html/database
chmod 666 /usr/share/nginx/html/database/test.db

一本花了一早上就看完的书,没啥收获。表示看不懂。都是在讲一些故事之类的。

20190706_172710.png

均线天数自定义,数量自定义,选出符合多头排列的股票。
增加索引,选股结果保存到 .csv 文件中

思路比较简单,根据选股策略,准备数据,然后执行策略,保存结果。

github 链接

下面是部分代码。

# 设置选股日期为最后一个有效交易日
valid_screen_date = get_last_valid_trade_date()
# [[func,param],[func,param]]
strategies = [[name_filter, ['ST']], [close_filter, 25], [ma_divergency, [10, 25, 43, 60]]]
# 市场,选股日期,[[func,param],[func,param]]
pickup_list = screen_stock('ALL', valid_screen_date, strategies)
print('选股策略执行完毕')
def screen_stock(market, screen_date, strategies):
"""
负责根据策略选股操作
:param market: 选股的市场,目前支持 ALL,SH,SZ 三种
:param screen_date: 指定选股日期
:param strategies: 指定选股策略
:return:
"""
# 如果数据为准备好,根据选股策略,获取对应的数据
if not g_is_data_prepared:
# 20秒
# start = time.clock()
datas = prepare_data(market, screen_date, strategies)
# end = time.clock()
# print('CPU执行时间: ', end - start)

pickup_list = []
for data in datas:
bFound = True
for row in strategies:
# 股票名称过滤策略在获取数据的时候应用,这里不需要执行
if row[0] == name_filter:
continue
# print(row)
pickup = row[0](data, row[1])
if pickup is None:
bFound = False
break
if bFound:
# print(pickup)
pickup_list.append(pickup)
return pickup_list

use PyMongo

Getting a Database

# attribute style access
db = client.test_database

# dictionary style access
db = client['test-database']

Getting a Collection

collection = db.test_collection
collection = db['test-collection']

集合是否存在

collection_list = dbDoc.collection_names()
if table_name not in collection_list:
pass

插入数据

collection.insert({'code': code, 'startDate': start_date, 'endDate': end_date, 'klines': klines})

Error

解决bson.errors.InvalidDocument: Cannot encode object:错误的一种方法
这是因为pandas库在读取数值型值时返回的结果不是整型或者浮点型,而是numpy.int64类型的一个对象,mongodb是无法对一个对象进行编码存储的,所以这里需要对读取到的结果进行强制类型转换
dates = []
for i in range(0, 2):
print(cal.iloc[i]['cal_date'], cal.iloc[i]['is_open'])
print(cal.iloc[i]['cal_date'] + ' %d' %cal.iloc[i]['is_open'])
a = int(cal.iloc[i]['is_open'])
print(type(a))
dates.append({'cal_date':cal.iloc[i]['cal_date'], 'is_open':int(cal.iloc[i]['is_open'])})

result = calender.insert_many(dates)
print(result)
print(result.inserted_ids)

连接数据库

import pymongo
conn = pymongo.MongoClient('127.0.0.1', 27017)
# database name is stock
db = conn['stock']

#有密码连接
import pymongo
mongo_client = pymongo.MongoClient('127.0.0.1', 26666)
mongo_auth = mongo_client.admin #或 mongo_client['admin'] admin为authenticationDatabase
mongo_auth.authenticate('用户名', '密码')

upsert

当key不存在的时候执行插入操作,当存在的时候更新除key以外的set内的值

最后的参数 True ,则是指明,当update不存在的_id时,执行插入操作。默认是false,只更新,不插入。

collectionConfig.update({'_id': resultConfig['id']}, {'$set': {'trade_data': 1}}, True)

单条插入

result = collection.insert_one(student)
print(result)
print(result.inserted_id)

批量插入

 # 创建集合,相当于表
t_codes = db['codes']
# 插入获取的代码
result = t_codes.insert_many(dataArr)
print(result)
print(result.inserted_ids)

索引

t_codes = db['codes']
# 获取所有索引
all_index = t_codes.index_information()
# print(list(all_index))
# 判断有无索引
has_id_index = all_index.get("idx_ts_code", False)
if has_id_index:
# 是否为唯一索引
if all_index['idx_ts_code'].get('unique', False):
pass
else:
t_codes.drop_index("idx_ts_code")
t_codes.create_index([("ts_code", 1)], name='idx_ts_code', unique=True, background=True)
else:
t_codes.create_index([("ts_code", 1)], name='idx_ts_code', unique=True, background=True)

删除集合

t_codes = db['codes']
t_codes.drop()
# 这里可以重新插入数据,会创建新的集合

# 也可以使用 db 操作
db.drop_collection(collection_name)

查找

返回是否为空

if not results.count():
print('not empty')
else:
print('empty')

查询返回 datafram

没有数据时返回 datafram 空值

t_data = db[code['ts_code']]
cursor_result = t_data.find(
{'ts_code': code['ts_code'], 'trade_date': {'$gte': start_date.strftime('%Y%m%d'),
'$lte': end_date.strftime('%Y%m%d')}}).sort('trade_date',
pymongo.DESCENDING)
labels = ['ts_code', 'trade_date', 'open', 'high', 'low', 'close', 'vol', 'amount']
df = pd.DataFrame(list(cursor_result), columns=labels)

查询一条

# 查询第一条数据
row = handler.find_one()
print(row)

# 最后一条
row = handler.find_one(sort=[('_id', -1)])

选择到 dataframe

t_codes = dbDoc['codes']
cursor = t_codes.find({'list_date':{'$lte': lt_date}}, {"_id": 0, "ts_code": 1, "name": 1, "list_date": 1})
fields = ['ts_code','name','list_date']
df = DataFrame(list(cursor), columns=fields)
return df

排序

rows = handler.find().sort('_id', -1)
for row in rows:
print(row) # 此时会倒序输出内容

查询所有数据

# 获得一个游标操作对象,并迭代
rows = handler.find()
for row in rows:
print(row)

时间范围

result = t_codes.find({'trade_date':{'$gte':start,'$lte':end}}).sort('trade_date', pymongo.DESCENDING)
# 查询集合中的所有文档记录(表中的行记录)
myColl.find()
# 返回一个查询结果的游标,可迭代对象

results = t_codes.find().sort('trade_date', pymongo.DESCENDING).limit(1)
start_trade_date = datetime.datetime.strptime(results[0]['trade_date'], '%Y%m%d')

result = t_calender.find(
{'cal_date': {'$gte': pre_base_date.strftime('%Y%m%d'),
'$lte': base_date.strftime('%Y%m%d')}}).sort('cal_date',
pymongo.DESCENDING)
for value in result:
if value['is_open']:
return datetime.datetime.strptime(value['cal_date'], '%Y%m%d')
print('Warning: xx')
b. 查询限定操作(也就是sql中的 where 语句)
i. myColl.find({'name':'liming'}) 查询集合中 字段 name = liming的记录
1) 注意:括号内部是一个 字典,或者 json格式的数据(其实都一个卵样)
2) 字典 key = 集合内文档的字段,value = 字段的值
3) 相当于sql中:
select *
from myColl
where name = 'liming'
ii. 一些高级操作:
1) 比较操作:
a) 小于比较:
i) myColl.find({'age':{'$lt':30}}
ii) 查询age字段值 小于30的所有文档记录
iii) 注意:括号内是一个 字典
iv) 字典 key = 文档字段,value 是一个字典,其中 key = 比较操作符, value =比较值
v) 相当于sql中:
select *
from myColl
where age < 30
b) 其他比较操作符
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
2) 组合查询:
a) 逻辑与 and
i) myColl.find({'name':'liming','age':30})
ii) 查询 name = liming 和 age = 30 的所有文档记录
iii) 注意:括号内是一个字典,两个元素。用 逗号分隔开,key = 字段,value=字段值
iv) 相当于sql:
select *
from myColl
where name = 'liming' and age = 30
b) 逻辑或 or
i) myColl.find({'$or':[{'name':'liming'},{'age':30}]})
ii) 查询name = 'liming' 或 age = 30的所有文档记录
iii) 注意:括号内是一个字典,key = '$or' 逻辑或操作符,value = 一个列表
列表内是两个字典,key = 字段,value=字段值
iv) 相当于sql:
select *
from myColl
where name = 'liming' or age = 30
3) 对查询结果进行排序:
a) myColl.find().sort('name',pymongo.DESCENDING)
i) 对查询结果按照字段 name进行排序,默认为升序,可以指定排序方向,
DESCENDING是降序
ii) 相当于sql:
select *
from myColl
order by name DESC
b) myColl.find().sort([{'name':pymongo.DESEDING',{'age':pymongo.DESEDING'}])
i) 对查询结果排序,指定排序方向为 降序,默认为升序。
先按照name字段排序,在按照age字段排序
ii) 相当于sql:
select *
from myColl
order by name DESC ,age DESC
DESC关键字只适用于 DESC前面的字段,需要的话,可以对每个字段指定一次 DESC

use PyMongo

Getting a Database

# attribute style access
db = client.test_database

# dictionary style access
db = client['test-database']

Getting a Collection

collection = db.test_collection
collection = db['test-collection']

插入数据

collection.insert({'code': code, 'startDate': start_date, 'endDate': end_date, 'klines': klines})

Error

解决bson.errors.InvalidDocument: Cannot encode object:错误的一种方法
这是因为pandas库在读取数值型值时返回的结果不是整型或者浮点型,而是numpy.int64类型的一个对象,mongodb是无法对一个对象进行编码存储的,所以这里需要对读取到的结果进行强制类型转换
dates = []
for i in range(0, 2):
print(cal.iloc[i]['cal_date'], cal.iloc[i]['is_open'])
print(cal.iloc[i]['cal_date'] + ' %d' %cal.iloc[i]['is_open'])
a = int(cal.iloc[i]['is_open'])
print(type(a))
dates.append({'cal_date':cal.iloc[i]['cal_date'], 'is_open':int(cal.iloc[i]['is_open'])})

result = calender.insert_many(dates)
print(result)
print(result.inserted_ids)

连接数据库

import pymongo
conn = pymongo.MongoClient('127.0.0.1', 27017)
# database name is stock
db = conn['stock']

单条插入

result = collection.insert_one(student)
print(result)
print(result.inserted_id)

批量插入

 # 创建集合,相当于表
t_codes = db['codes']
# 插入获取的代码
result = t_codes.insert_many(dataArr)
print(result)
print(result.inserted_ids)

索引

t_codes = db['codes']
# 获取所有索引
all_index = t_codes.index_information()
# print(list(all_index))
# 判断有无索引
has_id_index = all_index.get("idx_ts_code", False)
if has_id_index:
# 是否为唯一索引
if all_index['idx_ts_code'].get('unique', False):
pass
else:
t_codes.drop_index("idx_ts_code")
t_codes.create_index([("ts_code", 1)], name='idx_ts_code', unique=True, background=True)
else:
t_codes.create_index([("ts_code", 1)], name='idx_ts_code', unique=True, background=True)

删除集合

t_codes = db['codes']
t_codes.drop()
# 这里可以重新插入数据,会创建新的集合

# 也可以使用 db 操作
db.drop_collection(collection_name)

查找

返回是否为空

if not results.count():
print('not empty')
else:
print('empty')

查询返回 datafram

没有数据时返回 datafram 空值

t_data = db[code['ts_code']]
cursor_result = t_data.find(
{'ts_code': code['ts_code'], 'trade_date': {'$gte': start_date.strftime('%Y%m%d'),
'$lte': end_date.strftime('%Y%m%d')}}).sort('trade_date',
pymongo.DESCENDING)
labels = ['ts_code', 'trade_date', 'open', 'high', 'low', 'close', 'vol', 'amount']
df = pd.DataFrame(list(cursor_result), columns=labels)

查询所有数据

# 查询集合中的所有文档记录(表中的行记录)
myColl.find()
# 返回一个查询结果的游标,可迭代对象

results = t_codes.find().sort('trade_date', pymongo.DESCENDING).limit(1)
start_trade_date = datetime.datetime.strptime(results[0]['trade_date'], '%Y%m%d')

result = t_calender.find(
{'cal_date': {'$gte': pre_base_date.strftime('%Y%m%d'),
'$lte': base_date.strftime('%Y%m%d')}}).sort('cal_date',
pymongo.DESCENDING)
for value in result:
if value['is_open']:
return datetime.datetime.strptime(value['cal_date'], '%Y%m%d')
print('Warning: xx')
b. 查询限定操作(也就是sql中的 where 语句)
i. myColl.find({'name':'liming'}) 查询集合中 字段 name = liming的记录
1) 注意:括号内部是一个 字典,或者 json格式的数据(其实都一个卵样)
2) 字典 key = 集合内文档的字段,value = 字段的值
3) 相当于sql中:
select *
from myColl
where name = 'liming'
ii. 一些高级操作:
1) 比较操作:
a) 小于比较:
i) myColl.find({'age':{'$lt':30}}
ii) 查询age字段值 小于30的所有文档记录
iii) 注意:括号内是一个 字典
iv) 字典 key = 文档字段,value 是一个字典,其中 key = 比较操作符, value =比较值
v) 相当于sql中:
select *
from myColl
where age < 30
b) 其他比较操作符
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
2) 组合查询:
a) 逻辑与 and
i) myColl.find({'name':'liming','age':30})
ii) 查询 name = liming 和 age = 30 的所有文档记录
iii) 注意:括号内是一个字典,两个元素。用 逗号分隔开,key = 字段,value=字段值
iv) 相当于sql:
select *
from myColl
where name = 'liming' and age = 30
b) 逻辑或 or
i) myColl.find({'$or':[{'name':'liming'},{'age':30}]})
ii) 查询name = 'liming' 或 age = 30的所有文档记录
iii) 注意:括号内是一个字典,key = '$or' 逻辑或操作符,value = 一个列表
列表内是两个字典,key = 字段,value=字段值
iv) 相当于sql:
select *
from myColl
where name = 'liming' or age = 30
3) 对查询结果进行排序:
a) myColl.find().sort('name',pymongo.DESCENDING)
i) 对查询结果按照字段 name进行排序,默认为升序,可以指定排序方向,
DESCENDING是降序
ii) 相当于sql:
select *
from myColl
order by name DESC
b) myColl.find().sort([{'name':pymongo.DESEDING',{'age':pymongo.DESEDING'}])
i) 对查询结果排序,指定排序方向为 降序,默认为升序。
先按照name字段排序,在按照age字段排序
ii) 相当于sql:
select *
from myColl
order by name DESC ,age DESC
DESC关键字只适用于 DESC前面的字段,需要的话,可以对每个字段指定一次 DESC

2019.06.28为止的sql完整数据

github 链接

先获取 “股票代码表”

我这里是使用 mongodb 存储的。
项目有结构不方便放上来,这里是代码片段。具体请参见 github 仓库

def fetch_code():
"""
从接口获取代码,存入数据库,返回结构样例
ts_code symbol name area industry list_date
0 000001.SZ 000001 平安银行 深圳 银行 19910403
1 000002.SZ 000002 万科A 深圳 全国地产 19910129
3541 603936.SH 603936 博敏电子 广东 元器件 20151209
3542 603937.SH 603937 丽岛新材 江苏 铝 20171102
:return:
"""
# 查询当前所有正常上市交易的股票列表
datas = ts_pro.query('stock_basic', exchange='', list_status='L', fields='ts_code,symbol,name,area,industry,list_date')
dataArr = datas.to_dict('records')
# 创建集合,相当于表
t_codes = db['codes']
t_codes.drop()
# 插入获取的代码
result = t_codes.insert_many(dataArr)
if len(result.inserted_ids) != len(dataArr):
assert False
print('插入代码表数据失败.请检查。')
return
else:
print("插入代码表数据成功")

获取交易日历

def fetch_calender():
"""
从接口获取有效交易日信息,存入数据库,返回结构样例
exchange cal_date is_open
0 SSE 20180101 0
1 SSE 20180102 1
2 SSE 20180103 1
"""
calender = ts_pro.trade_cal(start_date='20190101', end_date='20191231')
# 创建集合,相当于表
t_calender = db['calender']
dataArr = calender.to_dict('records')
result = t_calender.insert_many(dataArr)
if len(result.inserted_ids) != len(dataArr):
assert False
print('插入代码表数据失败.请检查。')
return
else:
print("插入代码表数据成功")

获取历史数据

代码有些多,看 github 吧
每个股票代码作为一个集合保存数据。从数据库中取出代码,然后遍历获取数据

def get_code(market):
"""
获取股票代码表
market [in] string
SH 上海,SZ 深圳,ALL 所有市场
output:
{'ts_code': '600000.SH', 'symbol': '600000', 'name': '浦发银行', 'list_date': '19991110'}
:return:
"""
# 打开代码表集合
t_codes = db['codes']
if market == 'ALL':
codes = list(t_codes.find({}, {"_id": 0, "ts_code": 1, "symbol": 1, "name": 1, "industry": 1, "list_date": 1}))
else:
codes = list(t_codes.find({"ts_code": {"$regex": ".{}".format(market)}},
{"_id": 0, "ts_code": 1, "symbol": 1, "name": 1, "industry": 1, "list_date": 1}))
return codes

到这里基本数据就准备完毕了,在下一个笔记就可以选股操作了。

目前还不知道如何访问,下面类型的数据

[
{},{}
]

解析字符串

{
"key":[{},{}]
}
Document doc;
doc.Parse(strConfig.c_str());
ParseErrorCode error(kParseErrorNone);
error = doc.GetParseError();
if (error != kParseErrorNone)
{
return;
}
if (!doc.HasMember("dev_th") || !doc["dev_th"].IsArray())
{
return;
}
Value & arrAlarmHost = doc["dev_th"];
for (int index = 0; index < arrAlarmHost.Size(); ++index)
{
Value &objDev = arrAlarmHost[index];
if (!objDev.HasMember("port") || !objDev["port"].IsInt())
{
continue;
}
}

解析对象数组

"defendConfig" :
[
{
"addr" : "01234567",
"defendCode" : "008",
"name" : "东南角防区"
},
{
"addr" : "7654321",
"defendCode" : "009",
"name" : "西南角防区"
}
]

Document doc;
doc.Parse(m_sCmd.c_str());
ParseErrorCode error(kParseErrorNone);
if (false == doc.HasParseError() &&
doc.IsArray())
{
for (size_t i = 0; i < doc.Size(); ++i)
{
Value& v = doc[i];
tagDHFlowCountRegion region;
region.addr = v["addr"].GetInt();
region.defendCode = v["defendCode"].GetInt();
region.strName = v["name"].GetString();
m_vecConfig.emplace_back(region);
}
}

构建 json

/*
{
"layout":"2*2",
"Settings":
[
{
"group":"1",
"windows":"1#2",
"cycletime":"10",
"channels":
[
{
"loginID":"1234",
"channel":"2"
}
]
}
]
}
*/
void TestGenerateJsonArray()
{
string result = "";
rapidjson::StringBuffer strBuf;
//rapidjson::Writer<rapidjson::StringBuffer> writer(strBuf);
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strBuf);

writer.StartObject();
writer.Key("layout");
writer.String("2*2");


writer.Key("Settings");
writer.StartArray();
writer.StartObject();
writer.Key("group");
writer.String("1");
writer.Key("windows");
writer.String("1#2");
writer.Key("cycletime");
writer.String("10");
writer.Key("channels");
writer.StartArray();
writer.StartObject();
writer.Key("loginID");
writer.String("1234");
writer.Key("channel");
writer.String("2");
writer.EndObject();
writer.EndArray();
writer.EndObject();
writer.EndArray();
writer.EndObject();
result = strBuf.GetString();
cout << result << endl;
}
Document docHuminity; // Null
docHuminity.SetArray();
rapidjson::Document::AllocatorType& allocatorHuminity = docHuminity.GetAllocator();
for (auto it = m_mapDevInfo[id_cmd_chan].listChartDataTemperature.begin();it != m_mapDevInfo[id_cmd_chan].listChartDataTemperature.end();++it)
{
rapidjson::Value obj;
obj.SetObject();
obj.AddMember("name",rapidjson::StringRef(it->strName.c_str()),allocatorHuminity);

rapidjson::Value arr(rapidjson::kArrayType);
arr.PushBack(rapidjson::StringRef(it->strDatetime.c_str()), allocatorHuminity);
arr.PushBack(rapidjson::StringRef(it->strValue.c_str()), allocatorHuminity);

obj.AddMember("value",arr,allocatorHuminity);
docHuminity.PushBack(obj,allocatorHuminity);
}
rapidjson::StringBuffer bufferH;
rapidjson::Writer<rapidjson::StringBuffer> writerH(bufferH);
docHuminity.Accept(writerH);
strChartHumidity = bufferH.GetString();

对象数组

"value" : 
[
{
"addr" : "01234567",
"defendCode" : "008",
"name" : "东南角防区"
},
{
"addr" : "7654321",
"defendCode" : "009",
"name" : "西南角防区"
}
]

rapidjson::Document jsonDoc;
rapidjson::Document::AllocatorType &allocator = jsonDoc.GetAllocator(); //获取分配器
//将当前的Document设置为一个object,也就是说,整个Document是一个Object类型的dom元素
jsonDoc.SetObject();
//生成array
rapidjson::Value jsonArr(rapidjson::kArrayType);//创建一个Array类型的元素

for (auto iter = m_vecConfig.begin(); iter != m_vecConfig.end(); ++iter)
{
string sdev;
// 构建json字符串

// 添加属性
jsonDoc.AddMember("name", iter->strName, allocator);
jsonDoc.AddMember("addr", iter->strAddr, allocator);
jsonDoc.AddMember("defendCode", iter->strDefendCode, allocator);

jsonArr.PushBack(jsonDoc, allocator);
}

转字符串

std::string JsonToString(rapidjson::Value& valRoot)
{
    rapidjson::StringBuffer strBuf;
    strBuf.Clear();
    rapidjson::Writer<rapidjson::StringBuffer> writer(strBuf);
    valRoot.Accept(writer);
    std::string strJson = strBuf.GetString();
    return strJson;
}

综合样例

//生成一串如下的json格式字符串,并解析
// {
// "name":"qfl",
// "age":20,
// "letter":["a","b","c"],
// "location": {"province":"fujian","city":"xiamen","number":16}
// "book":[{"name":"book1", "isbn":"123"},{"name":"book2","isbn":"456"}],
// "healthy":true,
// }

//生成Json串
rapidjson::Document jsonDoc; //生成一个dom元素Document
rapidjson::Document::AllocatorType &allocator = jsonDoc.GetAllocator(); //获取分配器
jsonDoc.SetObject(); //将当前的Document设置为一个object,也就是说,整个Document是一个Object类型的dom元素

//添加属性
jsonDoc.AddMember("name", "qfl", allocator); //添加字符串值
jsonDoc.AddMember("age", 20, allocator); //添加int类型值

//生成array
rapidjson::Value letterArray(rapidjson::kArrayType);//创建一个Array类型的元素
letterArray.PushBack("a", allocator);
letterArray.PushBack("b", allocator);
letterArray.PushBack("c", allocator);
jsonDoc.AddMember("letter", letterArray, allocator); //添加数组

//生成一个object
rapidjson::Value locationObj(rapidjson::kObjectType);//创建一个Object类型的元素
locationObj.AddMember("province", "fujian", allocator);
locationObj.AddMember("city", "xiamen", allocator);
locationObj.AddMember("number", 16, allocator);
jsonDoc.AddMember("location", locationObj, allocator); //添加object到Document中

//生成一个object数组
rapidjson::Value bookArray(rapidjson::kArrayType);//生成一个Array类型的元素,用来存放Object
rapidjson::Value book1(rapidjson::kObjectType); //生成book1
book1.AddMember("name", "book1", allocator);
book1.AddMember("isbn", "123", allocator);
bookArray.PushBack(book1, allocator); //添加到数组

rapidjson::Value book2(rapidjson::kObjectType); //生成book2
book2.AddMember("name", "book2", allocator);
book2.AddMember("isbn", "456", allocator);
bookArray.PushBack(book2, allocator); //添加到数组
jsonDoc.AddMember("book", bookArray, allocator);

//添加属性
jsonDoc.AddMember("healthy", true, allocator); //添加bool类型值
// jsonDoc.AddMember("sports", NULL, allocator);//添加空值,这里会导致报错

//生成字符串
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
jsonDoc.Accept(writer);

std::string strJson = buffer.GetString();
log("-----生成的Json:\n%s", strJson.c_str());

//写到文件
std::string strPath = FileUtils::getInstance()->getWritablePath() + "JsonFile.txt";
FILE* myFile = fopen(strPath.c_str(), "w"); //windows平台要使用wb
if (myFile) {
fputs(buffer.GetString(), myFile);
fclose(myFile);
}

//JsonFile.txt文件内容
//{"name":"qfl","age":20,"letter":["a","b","c"],"location":{"province":"fujian","city":"xiamen","number":16},"book":[{"name":"book1","isbn":"123"},{"name":"book2","isbn":"456"}],"healthy":true}

log("-----读取Json内容:");
//从文件中读取(注意和上面分开,不能确定文件是否生成完毕,这里读取可能有问题)
rapidjson::Document newDoc;
myFile = fopen(strPath.c_str(), "r"); //windows平台使用rb
if (myFile) {
rapidjson::FileStream inputStream(myFile); //创建一个输入流
newDoc.ParseStream<0>(inputStream); //将读取的内容转换为dom元素
fclose(myFile); //关闭文件,很重要
}
//判断解析从流中读取的字符串是否有错误
if (newDoc.HasParseError()) {
log("Json Parse error:%d", newDoc.GetParseError()); //打印错误编号
}
else {
//获取json串中的数据
//先判断是否有这个字段,如果使用不存在的key去取值会导致直接崩溃
if (newDoc.HasMember("name")) {
log("name:%s", newDoc["name"].GetString()); //必须要获取对应的数据类型,rapidjson不会帮你转换类型
}
else {}

if (newDoc.HasMember("age")) {
log("age:%d", newDoc["age"].GetInt()); //获取正确的类型
}
else {}

if (newDoc.HasMember("letter")) {
rapidjson::Value letter; //使用一个新的rapidjson::Value来存放array的内容
letter = newDoc["letter"];

//确保它是一个Array,而且有内容
if (letter.IsArray() && !letter.Empty()) {
//遍历Array中的内容
for (rapidjson::SizeType i = 0; i < letter.Size(); i++) {
log("letter:%s", letter[i].GetString());
}
}
else {}
}
else {}

if (newDoc.HasMember("location")) {
rapidjson::Value location; //使用一个新的rapidjson::Value来存放object
location = newDoc["location"];

//确保它是一个Object
if (location.IsObject()) {

if (location.HasMember("province")) {
log("location:province:%s", location["province"].GetString());
}
else {}
if (location.HasMember("city")) {
log("location:city:%s", location["city"].GetString());
}
else {}
if (location.HasMember("number")) {
log("location:number:%d", location["number"].GetInt());
}
else {}
}
else {}
}
else {}

//book是一个包含了2个object的array。按照上面的步骤来取值就行
if (newDoc.HasMember("book")) {
rapidjson::Value book;
book = newDoc["book"];

//先取Array
if (book.IsArray() && !book.Empty()) {

rapidjson::Value tempBook;
for (rapidjson::SizeType i = 0; i < book.Size(); i++) {
tempBook = book[i]; //Array中每个元素又是一个Object

if (tempBook.IsObject()) {

if (tempBook.HasMember("name") && tempBook.HasMember("isbn")) {
log("book:%d:name:%s, isbn:%s", i, tempBook["name"].GetString(), tempBook["isbn"].GetString());
}
else {}
}
else {}
}
}
else {}
}
else {}

if (newDoc.HasMember("healthy")) {
if (newDoc["healthy"].GetBool()) {
log("healthy:true");
}
else {
log("healthy:false");
}
}
else {}
}