hikyuu2/hikyuu_cpp/hikyuu/KDataImp.cpp

431 lines
17 KiB
C++
Raw Normal View History

2015-01-07 01:26:14 +08:00
/*
* KDataImp.cpp
*
* Created on: 2013-2-4
* Author: fasiondog
*/
2020-10-05 00:07:29 +08:00
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
2015-01-07 01:26:14 +08:00
#include "StockManager.h"
#include "KDataImp.h"
namespace hku {
2020-11-01 14:01:08 +08:00
KDataImp::KDataImp() : m_start(0), m_end(0), m_have_pos_in_stock(false) {}
2015-01-07 01:26:14 +08:00
2019-11-10 19:45:57 +08:00
KDataImp::KDataImp(const Stock& stock, const KQuery& query)
2020-10-02 23:29:06 +08:00
: m_query(query), m_stock(stock), m_start(0), m_end(0), m_have_pos_in_stock(false) {
2015-01-07 01:26:14 +08:00
if (m_stock.isNull()) {
return;
}
2020-10-05 00:07:29 +08:00
m_buffer = m_stock.getKRecordList(query);
//不支持复权时,直接返回
if (query.recoverType() == KQuery::NO_RECOVER)
return;
//日线以上复权处理
if (query.kType() == KQuery::WEEK || query.kType() == KQuery::MONTH ||
query.kType() == KQuery::QUARTER || query.kType() == KQuery::HALFYEAR ||
query.kType() == KQuery::YEAR) {
_recoverForUpDay();
return;
}
switch (query.recoverType()) {
case KQuery::NO_RECOVER:
// do nothing
break;
case KQuery::FORWARD:
_recoverForward();
break;
case KQuery::BACKWARD:
_recoverBackward();
break;
case KQuery::EQUAL_FORWARD:
_recoverEqualForward();
break;
case KQuery::EQUAL_BACKWARD:
_recoverEqualBackward();
break;
default:
HKU_ERROR("Invalid RecvoerType!");
return;
}
2015-01-07 01:26:14 +08:00
}
2019-11-10 19:45:57 +08:00
KDataImp::~KDataImp() {}
2015-01-07 01:26:14 +08:00
2020-10-02 23:29:06 +08:00
size_t KDataImp::startPos() {
if (!m_have_pos_in_stock) {
_getPosInStock();
}
return m_start;
}
size_t KDataImp::endPos() {
if (!m_have_pos_in_stock) {
_getPosInStock();
}
return m_end;
}
size_t KDataImp::lastPos() {
if (!m_have_pos_in_stock) {
_getPosInStock();
}
return m_end == 0 ? 0 : m_end - 1;
}
void KDataImp::_getPosInStock() {
bool sucess = m_stock.getIndexRange(m_query, m_start, m_end);
if (!sucess) {
m_start = 0;
m_end = 0;
}
m_have_pos_in_stock = true;
}
size_t KDataImp::getPos(const Datetime& datetime) {
2020-10-05 00:07:29 +08:00
KRecordList::const_iterator iter;
KRecord comp_record;
comp_record.datetime = datetime;
boost::function<bool(const KRecord&, const KRecord&)> f =
boost::bind(&KRecord::datetime, _1) < boost::bind(&KRecord::datetime, _2);
iter = lower_bound(m_buffer.begin(), m_buffer.end(), comp_record, f);
if (iter == m_buffer.end() || iter->datetime != datetime) {
2016-04-03 00:08:31 +08:00
return Null<size_t>();
2015-01-07 01:26:14 +08:00
}
2020-10-05 00:07:29 +08:00
return (iter - m_buffer.begin());
}
void KDataImp::_recoverForUpDay() {
HKU_IF_RETURN(empty(), void());
2020-10-05 00:07:29 +08:00
std::function<Datetime(const Datetime&)> startOfPhase;
if (m_query.kType() == KQuery::WEEK) {
startOfPhase = &Datetime::startOfWeek;
} else if (m_query.kType() == KQuery::MONTH) {
startOfPhase = &Datetime::startOfMonth;
} else if (m_query.kType() == KQuery::QUARTER) {
startOfPhase = &Datetime::startOfQuarter;
} else if (m_query.kType() == KQuery::HALFYEAR) {
startOfPhase = &Datetime::startOfHalfyear;
} else if (m_query.kType() == KQuery::YEAR) {
startOfPhase = &Datetime::startOfYear;
}
Datetime startDate = startOfPhase(m_buffer.front().datetime);
Datetime endDate = m_buffer.back().datetime.nextDay();
KQuery query = KQueryByDate(startDate, endDate, KQuery::DAY, m_query.recoverType());
KData day_list = m_stock.getKData(query);
if (day_list.empty())
return;
size_t day_pos = 0;
size_t day_total = day_list.size();
size_t length = size();
for (size_t i = 0; i < length; i++) {
Datetime phase_start_date = startOfPhase(m_buffer[i].datetime);
Datetime phase_end_date = m_buffer[i].datetime;
if (day_pos >= day_total)
2015-01-07 01:26:14 +08:00
break;
2020-10-05 00:07:29 +08:00
while (day_list[day_pos].datetime < phase_start_date) {
day_pos++;
}
KRecord record = day_list[day_pos];
int pre_day_pos = day_pos;
while (day_pos < day_total && day_list[day_pos].datetime <= phase_end_date) {
if (day_list[day_pos].lowPrice < record.lowPrice) {
record.lowPrice = day_list[day_pos].lowPrice;
} else if (day_list[day_pos].highPrice > record.highPrice) {
record.highPrice = day_list[day_pos].highPrice;
}
record.closePrice = day_list[day_pos].closePrice;
day_pos++;
}
if (pre_day_pos != day_pos) {
m_buffer[i].openPrice = record.openPrice;
m_buffer[i].highPrice = record.highPrice;
m_buffer[i].lowPrice = record.lowPrice;
m_buffer[i].closePrice = record.closePrice;
2015-01-07 01:26:14 +08:00
}
2020-10-05 00:07:29 +08:00
}
2015-01-07 01:26:14 +08:00
2020-10-05 00:07:29 +08:00
return;
}
/******************************************************************************
* :[(-)()×]÷(1)
*
*
*
*
*****************************************************************************/
void KDataImp::_recoverForward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
2020-10-05 00:07:29 +08:00
Datetime start_date(m_buffer.front().datetime.date());
Datetime end_date(m_buffer.back().datetime.date() + bd::days(1));
StockWeightList weightList = m_stock.getWeight(start_date, end_date);
StockWeightList::const_iterator weightIter = weightList.begin();
StockWeightList::const_iterator pre_weightIter = weightIter;
size_t pre_pos = 0;
for (; weightIter != weightList.end(); ++weightIter) {
size_t i = pre_pos;
while (i < total && m_buffer[i].datetime < weightIter->datetime()) {
i++;
}
pre_pos = i; //除权日
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
price_t change = 0.0;
bool flag = false;
if (weightIter != weightList.begin() &&
!(weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0))
//&& weightIter->bonus() == 0.0
//&& weightIter->increasement() == 0.0 ))
{
pre_weightIter = weightIter - 1;
if (pre_weightIter->freeCount() != 0.0) {
change = (weightIter->freeCount() - pre_weightIter->freeCount()) /
pre_weightIter->freeCount();
flag = true;
}
}
if (!flag) {
change = 0.1 * (weightIter->countAsGift() + weightIter->countForSell() +
weightIter->increasement());
2015-01-07 01:26:14 +08:00
}
2020-10-05 00:07:29 +08:00
price_t denominator = 1.0 + change; //分母 = (1+流通股份变动比例)
price_t temp = weightIter->priceForSell() * change - 0.1 * weightIter->bonus();
for (i = 0; i < pre_pos; ++i) {
m_buffer[i].openPrice =
roundEx((m_buffer[i].openPrice + temp) / denominator, m_stock.precision());
m_buffer[i].highPrice =
roundEx((m_buffer[i].highPrice + temp) / denominator, m_stock.precision());
m_buffer[i].lowPrice =
roundEx((m_buffer[i].lowPrice + temp) / denominator, m_stock.precision());
m_buffer[i].closePrice =
roundEx((m_buffer[i].closePrice + temp) / denominator, m_stock.precision());
2015-01-07 01:26:14 +08:00
}
}
2020-10-05 00:07:29 +08:00
}
2015-01-07 01:26:14 +08:00
2020-10-05 00:07:29 +08:00
/******************************************************************************
* :×(1)-()×
*
*
*
*****************************************************************************/
void KDataImp::_recoverBackward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
2020-10-05 00:07:29 +08:00
Datetime start_date(m_buffer.front().datetime.date());
Datetime end_date(m_buffer.back().datetime.date() + bd::days(1));
StockWeightList weightList = m_stock.getWeight(start_date, end_date);
StockWeightList::const_reverse_iterator weightIter = weightList.rbegin();
StockWeightList::const_reverse_iterator pre_weightIter;
size_t pre_pos = total - 1;
for (; weightIter != weightList.rend(); ++weightIter) {
size_t i = pre_pos;
while (i > 0 && m_buffer[i].datetime > weightIter->datetime()) {
i--;
}
pre_pos = i;
//流通股份变动比例
price_t change = 0.0;
bool flag = false;
pre_weightIter = weightIter + 1;
if (pre_weightIter != weightList.rend() && pre_weightIter->freeCount() != 0.0 &&
!(weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0))
//&& weightIter->bonus() == 0.0
//&& weightIter->increasement() == 0.0 ))
{
change =
(weightIter->freeCount() - pre_weightIter->freeCount()) / pre_weightIter->freeCount();
flag = true;
}
if (!flag) {
change = 0.1 * (weightIter->countAsGift() + weightIter->countForSell() +
weightIter->increasement());
}
price_t denominator = 1.0 + change; //(1+流通股份变动比例)
price_t temp = 0.1 * weightIter->bonus() - weightIter->priceForSell() * change;
;
for (i = pre_pos; i < total; ++i) {
m_buffer[i].openPrice =
roundEx(m_buffer[i].openPrice * denominator + temp, m_stock.precision());
m_buffer[i].highPrice =
roundEx(m_buffer[i].highPrice * denominator + temp, m_stock.precision());
m_buffer[i].lowPrice =
roundEx(m_buffer[i].lowPrice * denominator + temp, m_stock.precision());
m_buffer[i].closePrice =
roundEx(m_buffer[i].closePrice * denominator + temp, m_stock.precision());
}
2015-01-07 01:26:14 +08:00
}
2020-10-05 00:07:29 +08:00
}
/******************************************************************************
* :*
* [(-)()×]÷(1)÷
*
*
*
*
*****************************************************************************/
void KDataImp::_recoverEqualForward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
2020-10-05 00:07:29 +08:00
Datetime start_date(m_buffer.front().datetime.date());
Datetime end_date(m_buffer.back().datetime.date() + bd::days(1));
StockWeightList weightList = m_stock.getWeight(start_date, end_date);
if (weightList.empty()) {
return;
}
KRecordList kdata = m_buffer; //防止同一天两条权息记录
StockWeightList::const_iterator weightIter = weightList.begin();
StockWeightList::const_iterator pre_weightIter;
size_t pre_pos = 0;
for (; weightIter != weightList.end(); ++weightIter) {
size_t i = pre_pos;
while (i < total && m_buffer[i].datetime < weightIter->datetime()) {
i++;
}
pre_pos = i; //除权日
//股权登记日(即除权日的前一天数据)收盘价
if (pre_pos == 0) {
continue;
}
price_t closePrice = kdata[pre_pos - 1].closePrice;
if (closePrice == 0.0) {
continue; //除零保护
}
2015-01-07 01:26:14 +08:00
2020-10-05 00:07:29 +08:00
//流通股份变动比例
price_t change = 0.0;
bool flag = false;
if (weightIter != weightList.begin() &&
!(weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0))
//&& weightIter->bonus() == 0.0
//&& weightIter->increasement() == 0.0 ))
{
pre_weightIter = weightIter - 1;
if (pre_weightIter->freeCount() != 0.0) {
change = (weightIter->freeCount() - pre_weightIter->freeCount()) /
pre_weightIter->freeCount();
flag = true;
}
}
if (!flag) {
change = 0.1 * (weightIter->countAsGift() + weightIter->countForSell() +
weightIter->increasement());
}
price_t denominator = 1.0 + change; //(1+流通股份变动比例)
price_t temp = weightIter->priceForSell() * change - 0.1 * weightIter->bonus();
price_t k = (closePrice + temp) / (denominator * closePrice);
for (i = 0; i < pre_pos; ++i) {
m_buffer[i].openPrice = roundEx(k * m_buffer[i].openPrice, m_stock.precision());
m_buffer[i].highPrice = roundEx(k * m_buffer[i].highPrice, m_stock.precision());
m_buffer[i].lowPrice = roundEx(k * m_buffer[i].lowPrice, m_stock.precision());
m_buffer[i].closePrice = roundEx(k * m_buffer[i].closePrice, m_stock.precision());
}
}
}
/******************************************************************************
* :÷
* [(-)()×]÷(1)÷
*
*
*
*****************************************************************************/
void KDataImp::_recoverEqualBackward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
2020-10-05 00:07:29 +08:00
Datetime start_date(m_buffer.front().datetime.date());
Datetime end_date(m_buffer.back().datetime.date() + bd::days(1));
StockWeightList weightList = m_stock.getWeight(start_date, end_date);
StockWeightList::const_reverse_iterator weightIter = weightList.rbegin();
StockWeightList::const_reverse_iterator pre_weightIter;
size_t pre_pos = total - 1;
for (; weightIter != weightList.rend(); ++weightIter) {
size_t i = pre_pos;
while (i > 0 && m_buffer[i].datetime > weightIter->datetime()) {
i--;
}
pre_pos = i; //除权日
//股权登记日(即除权日的前一天数据)收盘价
if (pre_pos == 0) {
continue;
}
price_t closePrice = m_buffer[pre_pos - 1].closePrice;
//流通股份变动比例
price_t change = 0.0;
bool flag = false;
pre_weightIter = weightIter + 1;
if (pre_weightIter != weightList.rend() && pre_weightIter->freeCount() != 0.0 &&
!(weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0))
//&& weightIter->bonus() == 0.0
//&& weightIter->increasement() == 0.0 ))
{
change =
(weightIter->freeCount() - pre_weightIter->freeCount()) / pre_weightIter->freeCount();
flag = true;
}
if (!flag) {
change = 0.1 * (weightIter->countAsGift() + weightIter->countForSell() +
weightIter->increasement());
}
price_t denominator = 1.0 + change; //(1+流通股份变动比例)
price_t temp = closePrice + weightIter->priceForSell() * change - 0.1 * weightIter->bonus();
if (temp == 0.0) {
continue;
}
price_t k = (denominator * closePrice) / temp;
for (i = pre_pos; i < total; ++i) {
m_buffer[i].openPrice = roundEx(k * m_buffer[i].openPrice, m_stock.precision());
m_buffer[i].highPrice = roundEx(k * m_buffer[i].highPrice, m_stock.precision());
m_buffer[i].lowPrice = roundEx(k * m_buffer[i].lowPrice, m_stock.precision());
m_buffer[i].closePrice = roundEx(k * m_buffer[i].closePrice, m_stock.precision());
}
}
2015-01-07 01:26:14 +08:00
}
} /* namespace hku */