This commit is contained in:
fasiondog 2022-03-11 22:37:21 +08:00
commit 00d61ffdf6
4 changed files with 504 additions and 467 deletions

View File

@ -5,11 +5,9 @@
* Author: fasiondog
*/
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include "KData.h"
#include "StockManager.h"
#include "KDataImp.h"
#include "indicator/crt/KDATA.h"
#include <fstream>
@ -28,101 +26,15 @@ string KData::toString() const {
return os.str();
}
KData::KData(const Stock& stock, const KQuery& query)
: m_query(query), m_raw_query(query), m_stock(stock), m_start(0), m_end(0) {
if (m_stock.isNull()) {
return;
KData::KData(const Stock& stock, const KQuery& query) {
if (!stock.isNull()) {
m_imp = KDataImpPtr(new KDataImp(stock, query));
}
bool sucess = m_stock.getIndexRange(query, m_start, m_end);
m_query = KQueryByIndex(m_start, m_end, query.kType(), query.recoverType());
if (!sucess) {
m_start = 0;
m_end = 0;
return;
}
m_buffer = m_stock.getKRecordList(m_query);
//不支持复权时,直接返回
if (m_query.recoverType() == KQuery::NO_RECOVER)
return;
//日线以上复权处理
if (m_query.kType() == KQuery::WEEK || m_query.kType() == KQuery::MONTH ||
m_query.kType() == KQuery::QUARTER || m_query.kType() == KQuery::HALFYEAR ||
m_query.kType() == KQuery::YEAR) {
_recoverForUpDay();
return;
}
switch (m_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;
}
}
KData::KData(const KData& x)
: m_buffer(x.m_buffer),
m_query(x.m_query),
m_raw_query(x.m_raw_query),
m_stock(x.m_stock),
m_start(x.m_start),
m_end(x.m_end) {}
KData::KData(KData&& x)
: m_buffer(std::move(x.m_buffer)),
m_query(x.m_query),
m_raw_query(x.m_raw_query),
m_stock(std::move(x.m_stock)),
m_start(x.m_start),
m_end(x.m_end) {}
KData& KData::operator=(const KData& x) {
HKU_IF_RETURN(this == &x, *this);
m_buffer = x.m_buffer;
m_stock = x.m_stock;
m_query = x.m_query;
m_raw_query = x.m_raw_query;
m_start = x.m_start;
m_end = x.m_end;
return *this;
}
KData& KData::operator=(KData&& x) {
HKU_IF_RETURN(this == &x, *this);
m_buffer = std::move(x.m_buffer);
m_stock = std::move(x.m_stock);
m_query = x.m_query;
m_raw_query = x.m_raw_query;
m_start = x.m_start;
m_end = x.m_end;
return *this;
}
bool KData::operator==(const KData& thr) {
return this == &thr || (getStock() == thr.getStock() && getQuery() == thr.getQuery());
return this == &thr || m_imp == thr.m_imp ||
(getStock() == thr.getStock() && getQuery() == thr.getQuery());
}
size_t KData::getPosInStock(Datetime datetime) const {
@ -130,341 +42,6 @@ size_t KData::getPosInStock(Datetime datetime) const {
return pos == Null<size_t>() ? Null<size_t>() : pos + startPos();
}
size_t KData::getPos(const Datetime& datetime) const {
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) {
return Null<size_t>();
}
return (iter - m_buffer.begin());
}
DatetimeList KData::getDatetimeList() const {
DatetimeList result;
if (empty()) {
return result;
}
result = getStock().getDatetimeList(KQuery(startPos(), lastPos() + 1, getQuery().kType()));
return result;
}
size_t KData::expand(size_t num) {
HKU_IF_RETURN(m_stock.isNull() || m_end >= m_stock.getCount(m_query.kType()), 0);
KQuery query;
if (m_raw_query.queryType() == KQuery::INDEX) {
query = KQueryByIndex(m_end, m_end + num, m_raw_query.kType(), m_raw_query.recoverType());
} else {
query = KQueryByDate(m_raw_query.endDatetime(), Datetime::max(), m_raw_query.kType(),
m_raw_query.recoverType());
size_t start = 0, end = 0;
bool success = m_stock.getIndexRange(query, start, end);
HKU_IF_RETURN(!success, 0);
query = KQueryByIndex(start, start + num, m_raw_query.kType(), m_raw_query.recoverType());
}
KRecordList records = m_stock.getKRecordList(query);
HKU_IF_RETURN(records.empty(), 0);
size_t count = 0;
for (auto& record : records) {
m_buffer.emplace_back(record);
count++;
}
m_end += count;
m_query = KQueryByIndex(m_start, m_end, m_query.kType(), m_query.recoverType());
if (m_raw_query.queryType() == KQuery::DATE) {
if (size() > 0) {
m_raw_query = KQueryByDate(m_raw_query.startDatetime(),
m_buffer[size() - 1].datetime + TimeDelta(1),
m_raw_query.kType(), m_raw_query.recoverType());
}
} else {
m_raw_query = m_query;
}
return count;
}
void KData::_recoverForUpDay() {
HKU_IF_RETURN(empty(), void());
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)
break;
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;
}
}
return;
}
/******************************************************************************
* :[(-)()×]÷(1)
*
*
*
*
*****************************************************************************/
void KData::_recoverForward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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) {
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
if ((weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0 && weightIter->bonus() == 0.0 &&
weightIter->increasement() == 0.0))
continue;
size_t i = pre_pos;
while (i < total && m_buffer[i].datetime < weightIter->datetime()) {
i++;
}
pre_pos = i; //除权日
price_t 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();
if (denominator == 1.0 && temp == 0.0)
continue;
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());
}
}
}
/******************************************************************************
* :×(1)-()×
*
*
*
*****************************************************************************/
void KData::_recoverBackward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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) {
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
if ((weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0 && weightIter->bonus() == 0.0 &&
weightIter->increasement() == 0.0))
continue;
size_t i = pre_pos;
while (i > 0 && m_buffer[i].datetime > weightIter->datetime()) {
i--;
}
pre_pos = i;
//流通股份变动比例
price_t 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;
if (denominator == 1.0 && temp == 0.0)
continue;
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());
}
}
}
/******************************************************************************
* :*
* [(-)()×]÷(1)÷
*
*
*
*
*****************************************************************************/
void KData::_recoverEqualForward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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) {
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
if ((weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0 && weightIter->bonus() == 0.0 &&
weightIter->increasement() == 0.0))
continue;
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; //除零保护
}
//流通股份变动比例
price_t 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();
if (denominator == 0.0 || (denominator == 1.0 && temp == 0.0))
continue;
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 KData::_recoverEqualBackward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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.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 || denominator == 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());
}
}
}
void KData::tocsv(const string& filename) {
std::ofstream file(filename.c_str());
HKU_ERROR_IF_RETURN(!file, void(), "Can't open file! ({})", filename);

View File

@ -9,7 +9,7 @@
#ifndef KDATA_H_
#define KDATA_H_
#include "Stock.h"
#include "KDataImp.h"
namespace hku {
@ -45,7 +45,7 @@ public:
/** 同getKRecord @see getKRecord */
KRecord operator[](size_t pos) const {
return m_buffer[pos];
return getKRecord(pos);
}
/** 同getKRecord @see getKRecord */
@ -59,12 +59,9 @@ public:
/** 按日期获取在原始 K 线记录中的位置 */
size_t getPosInStock(Datetime datetime) const;
/** 获取关联的KQuery, 该 Query 已被同一调整为按索引方式的查询条件 */
/** 获取关联的KQuery */
KQuery getQuery() const;
/** 获取原始查询条件 */
KQuery getRawQUery() const;
/** 获取关联的Stock如果没有关联返回Null<Stock> */
Stock getStock() const;
@ -77,13 +74,6 @@ public:
/** 获取在原始K线记录中对应范围的下一条记录的位置如果为空返回0,其他等于lastPos + 1 */
size_t endPos() const;
/**
* Stock KRecord
* @param num
* @return size_t
*/
size_t expand(size_t num);
/** 输出数据到指定的文件中 */
void tocsv(const string& filename);
@ -108,19 +98,7 @@ public:
Indicator amo() const;
private:
void _recoverForward();
void _recoverBackward();
void _recoverEqualForward();
void _recoverEqualBackward();
void _recoverForUpDay();
private:
KRecordList m_buffer;
KQuery m_query;
KQuery m_raw_query;
Stock m_stock;
size_t m_start;
size_t m_end;
KDataImpPtr m_imp;
};
/**
@ -171,8 +149,35 @@ KData HKU_API getKData(const string& market_code, int64_t start = 0, int64_t end
KQuery::KType ktype = KQuery::DAY,
KQuery::RecoverType recoverType = KQuery::NO_RECOVER);
inline KData::KData(const KData& x) : m_imp(x.m_imp) {}
inline KData::KData(KData&& x) : m_imp(std::move(x.m_imp)) {}
inline KData& KData::operator=(const KData& x) {
if (this == &x)
return *this;
m_imp = x.m_imp;
return *this;
}
inline KData& KData::operator=(KData&& x) {
if (this == &x)
return *this;
m_imp = std::move(x.m_imp);
return *this;
}
inline DatetimeList KData::getDatetimeList() const {
DatetimeList result;
if (empty()) {
return result;
}
result = getStock().getDatetimeList(KQuery(startPos(), lastPos() + 1, getQuery().kType()));
return result;
}
inline KRecord KData::getKRecord(size_t pos) const {
return m_buffer[pos];
return m_imp->getKRecord(pos); //如果为空,将抛出异常
}
inline KRecord KData::getKRecord(Datetime datetime) const {
@ -180,36 +185,36 @@ inline KRecord KData::getKRecord(Datetime datetime) const {
return pos != Null<size_t>() ? getKRecord(pos) : Null<KRecord>();
}
inline size_t KData::getPos(const Datetime& datetime) const {
return m_imp ? m_imp->getPos(datetime) : Null<size_t>();
}
inline size_t KData::size() const {
return m_buffer.size();
return m_imp ? m_imp->size() : 0;
}
inline bool KData::empty() const {
return m_buffer.empty();
return m_imp ? m_imp->empty() : true;
}
inline KQuery KData::getQuery() const {
return m_query;
}
inline KQuery KData::getRawQUery() const {
return m_raw_query;
return m_imp ? m_imp->getQuery() : Null<KQuery>();
}
inline Stock KData::getStock() const {
return m_stock;
return m_imp ? m_imp->getStock() : Null<Stock>();
}
inline size_t KData::startPos() const {
return m_start;
return m_imp ? m_imp->startPos() : 0;
}
inline size_t KData::endPos() const {
return m_end;
return m_imp ? m_imp->endPos() : 0;
}
inline size_t KData::lastPos() const {
return m_end == 0 ? 0 : m_end - 1;
return m_imp ? m_imp->lastPos() : 0;
}
} /* namespace hku */

View File

@ -0,0 +1,387 @@
/*
* KDataImp.cpp
*
* Created on: 2013-2-4
* Author: fasiondog
*/
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include "StockManager.h"
#include "KDataImp.h"
namespace hku {
KDataImp::KDataImp() : m_start(0), m_end(0), m_have_pos_in_stock(false) {}
KDataImp::KDataImp(const Stock& stock, const KQuery& query)
: m_query(query), m_stock(stock), m_start(0), m_end(0), m_have_pos_in_stock(false) {
if (m_stock.isNull()) {
return;
}
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;
}
}
KDataImp::~KDataImp() {}
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) {
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) {
return Null<size_t>();
}
return (iter - m_buffer.begin());
}
void KDataImp::_recoverForUpDay() {
HKU_IF_RETURN(empty(), void());
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)
break;
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;
}
}
return;
}
/******************************************************************************
* :[(-)()×]÷(1)
*
*
*
*
*****************************************************************************/
void KDataImp::_recoverForward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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) {
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
if ((weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0 && weightIter->bonus() == 0.0 &&
weightIter->increasement() == 0.0))
continue;
size_t i = pre_pos;
while (i < total && m_buffer[i].datetime < weightIter->datetime()) {
i++;
}
pre_pos = i; //除权日
price_t 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();
if (denominator == 1.0 && temp == 0.0)
continue;
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());
}
}
}
/******************************************************************************
* :×(1)-()×
*
*
*
*****************************************************************************/
void KDataImp::_recoverBackward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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) {
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
if ((weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0 && weightIter->bonus() == 0.0 &&
weightIter->increasement() == 0.0))
continue;
size_t i = pre_pos;
while (i > 0 && m_buffer[i].datetime > weightIter->datetime()) {
i--;
}
pre_pos = i;
//流通股份变动比例
price_t 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;
if (denominator == 1.0 && temp == 0.0)
continue;
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());
}
}
}
/******************************************************************************
* :*
* [(-)()×]÷(1)÷
*
*
*
*
*****************************************************************************/
void KDataImp::_recoverEqualForward() {
size_t total = m_buffer.size();
HKU_IF_RETURN(total == 0, void());
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) {
//计算流通股份变动比例,但不处理仅仅只有流通股本改变的情况
if ((weightIter->countAsGift() == 0.0 && weightIter->countForSell() == 0.0 &&
weightIter->priceForSell() == 0.0 && weightIter->bonus() == 0.0 &&
weightIter->increasement() == 0.0))
continue;
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; //除零保护
}
//流通股份变动比例
price_t 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();
if (denominator == 0.0 || (denominator == 1.0 && temp == 0.0))
continue;
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());
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.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 || denominator == 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());
}
}
}
} /* namespace hku */

View File

@ -0,0 +1,68 @@
/*
* KDataImp.h
*
* Created on: 2013-2-4
* Author: fasiondog
*/
#pragma once
#ifndef KDATAIMP_H_
#define KDATAIMP_H_
#include "Stock.h"
namespace hku {
class KDataImp {
public:
KDataImp();
KDataImp(const Stock& stock, const KQuery& query);
virtual ~KDataImp();
KQuery getQuery() const {
return m_query;
}
Stock getStock() const {
return m_stock;
}
KRecord getKRecord(size_t pos) const {
return m_buffer[pos];
}
bool empty() const {
return m_buffer.empty();
}
size_t size() {
return m_buffer.size();
}
size_t startPos();
size_t endPos();
size_t lastPos();
size_t getPos(const Datetime& datetime);
private:
void _getPosInStock();
void _recoverForward();
void _recoverBackward();
void _recoverEqualForward();
void _recoverEqualBackward();
void _recoverForUpDay();
private:
KRecordList m_buffer;
KQuery m_query;
Stock m_stock;
size_t m_start;
size_t m_end;
bool m_have_pos_in_stock;
};
typedef shared_ptr<KDataImp> KDataImpPtr;
} /* namespace hku */
#endif /* KDATAIMP_H_ */