mirror of
https://gitee.com/fasiondog/hikyuu.git
synced 2024-12-02 03:48:19 +08:00
Merge branch 'develop' of https://gitee.com/fasiondog/hikyuu
This commit is contained in:
commit
00d61ffdf6
@ -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);
|
||||
|
@ -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 */
|
||||
|
387
hikyuu_cpp/hikyuu/KDataImp.cpp
Normal file
387
hikyuu_cpp/hikyuu/KDataImp.cpp
Normal 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 */
|
68
hikyuu_cpp/hikyuu/KDataImp.h
Normal file
68
hikyuu_cpp/hikyuu/KDataImp.h
Normal 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_ */
|
Loading…
Reference in New Issue
Block a user