Skip to content

Commit

Permalink
Merge pull request #217 from fasiondog/feature/factor
Browse files Browse the repository at this point in the history
SG support cycle
  • Loading branch information
fasiondog committed Apr 2, 2024
2 parents b77d0cc + 966c8e6 commit 26da56f
Show file tree
Hide file tree
Showing 31 changed files with 251 additions and 153 deletions.
13 changes: 6 additions & 7 deletions docs/examples/quick_crtsg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
# -*- coding: utf8 -*-
# cp936

#===============================================================================
# ===============================================================================
# Aothor: fasiondog
# History: 20160407, Added by fasiondog
#===============================================================================
# ===============================================================================

from hikyuu import *


def TurtleSG(self):
def TurtleSG(self, k):
n = self.get_param("n")
k = self.to
c = CLOSE(k)
h = REF(HHV(c, n), 1) #前n日高点
L = REF(LLV(c, n), 1) #前n日低点
h = REF(HHV(c, n), 1) # 前n日高点
L = REF(LLV(c, n), 1) # 前n日低点
for i in range(h.discard, len(k)):
if (c[i] >= h[i]):
self._add_buy_signal(k[i].datetime)
Expand All @@ -30,7 +29,7 @@ def TurtleSG(self):
s = get_stock("sh000001")
k = s.get_kdata(Query(-500))

#只有设置交易对象时,才会开始实际计算
# 只有设置交易对象时,才会开始实际计算
sg.to = k
dates = k.get_datetime_list()
for d in dates:
Expand Down
8 changes: 8 additions & 0 deletions docs/source/base/datatype.rst
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,14 @@ K线数据
获取关联的Stock

:rtype: Stock

.. py:method:: get_kdata()
通过当前 KData 获取一个保持数据类型、复权类型不变的新的 KData(注意,不是原 KData 的子集)

:param Datetime start: 新的起始日期
:param Datetime end: 新的结束日期
:rtype: KData

.. py:method:: tocsv(filename)
Expand Down
13 changes: 6 additions & 7 deletions hikyuu/examples/Turtle_SG.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# -*- coding: utf8 -*-
# cp936

#===============================================================================
# ===============================================================================
# Aothor: fasiondog
# History: 20160407, Added by fasiondog
#===============================================================================
# ===============================================================================

from hikyuu import *

Expand All @@ -18,12 +18,11 @@ def __init__(self, n=20):
def _clone(self):
return TurtleSignal()

def _calculate(self):
def _calculate(self, k):
n = self.get_param("n")
k = self.to
c = CLOSE(k)
h = REF(HHV(c, n), 1) #前n日高点
L = REF(LLV(c, n), 1) #前n日低点
h = REF(HHV(c, n), 1) # 前n日高点
L = REF(LLV(c, n), 1) # 前n日低点
for i in range(h.discard, len(k)):
if (c[i] >= h[i]):
self._add_buy_signal(k[i].datetime)
Expand All @@ -38,7 +37,7 @@ def _calculate(self):
s = get_stock("sh000001")
k = s.get_kdata(Query(-500))

#只有设置交易对象时,才会开始实际计算
# 只有设置交易对象时,才会开始实际计算
sg.to = k
dates = k.get_datetime_list()
for d in dates:
Expand Down
12 changes: 6 additions & 6 deletions hikyuu/examples/quick_crtsg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
# -*- coding: utf8 -*-
# cp936

#===============================================================================
# ===============================================================================
# Aothor: fasiondog
# History: 20160407, Added by fasiondog
#===============================================================================
# ===============================================================================

from hikyuu import *


def TurtleSG(self):
def TurtleSG(self, k):
n = self.get_param("n")
k = self.to
c = CLOSE(k)
h = REF(HHV(c, n), 1) #前n日高点
L = REF(LLV(c, n), 1) #前n日低点
h = REF(HHV(c, n), 1) # 前n日高点
L = REF(LLV(c, n), 1) # 前n日低点
for i in range(h.discard, len(k)):
if (c[i] >= h[i]):
self._add_buy_signal(k[i].datetime)
Expand All @@ -30,7 +30,7 @@ def TurtleSG(self):
s = get_stock("sh000001")
k = s.get_kdata(Query(-500))

#只有设置交易对象时,才会开始实际计算
# 只有设置交易对象时,才会开始实际计算
sg.to = k
dates = k.get_datetime_list()
for d in dates:
Expand Down
4 changes: 2 additions & 2 deletions hikyuu/test/Signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def _clone(self):
p._x = self._x
return p

def _calculate(self):
def _calculate(self, kdata):
self._add_buy_signal(Datetime(201201210000))
self._add_sell_signal(Datetime(201201300000))

Expand Down Expand Up @@ -91,7 +91,7 @@ def test_SignalBase(self):
self.assertEqual(p_clone.get_param("test"), 30)


def testSignal(self):
def testSignal(self, kdata):
self._add_buy_signal(Datetime(201201210000))
self._add_sell_signal(Datetime(201201300000))

Expand Down
10 changes: 10 additions & 0 deletions hikyuu_cpp/hikyuu/KData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ void KData::tocsv(const string& filename) {
file.close();
}

KData KData::getKData(const Datetime& start, const Datetime& end) const {
const Stock& stk = getStock();
if (stk.isNull()) {
return KData();
}

const KQuery& query = getQuery();
return KData(stk, KQueryByDate(start, end, query.kType(), query.recoverType()));
}

Indicator KData::open() const {
return OPEN(*this);
}
Expand Down
8 changes: 8 additions & 0 deletions hikyuu_cpp/hikyuu/KData.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ class HKU_API KData {
return getKRecord(datetime);
}

/**
* 通过当前 KData 获取一个保持数据类型、复权类型不变的新的 KData
* @note 新的 KData 并不一定是原 KData 的子集
* @param start 起始日期
* @param end 结束日期
*/
KData getKData(const Datetime& start, const Datetime& end) const;

/** 按日期查询对应的索引位置,注:是 KData 中的位置,不是在 Stock 中原始K记录的位置 */
size_t getPos(const Datetime& datetime) const;

Expand Down
112 changes: 23 additions & 89 deletions hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ Portfolio::Portfolio(const TradeManagerPtr& tm, const SelectorPtr& se, const AFP
Portfolio::~Portfolio() {}

void Portfolio::initParam() {
setParam<int>("adjust_cycle", 1); // 调仓周期
setParam<bool>("trace", false); // 打印跟踪
setParam<int>("adjust_cycle", 1); // 调仓周期
setParam<bool>("trace", false); // 打印跟踪
setParam<int>("trace_max_num", 10); // 打印跟踪时,显示当前持仓证券最大数量
}

void Portfolio::baseCheckParam(const string& name) const {
Expand All @@ -72,7 +73,6 @@ void Portfolio::paramChanged() {
void Portfolio::reset() {
m_real_sys_list.clear();
m_running_sys_set.clear();
m_failed_sys_map.clear();
m_dlist_sys_list.clear();
m_delay_adjust_sys_list.clear();
m_tmp_selected_list.clear();
Expand Down Expand Up @@ -173,15 +173,18 @@ void Portfolio::run(const KQuery& query, int adjust_cycle, bool force) {
HKU_IF_RETURN(datelist.empty(), void());

size_t cur_adjust_ix = 0;
Datetime cur_cycle_end;
for (size_t i = 0, total = datelist.size(); i < total; i++) {
bool adjust = false;
if (i == cur_adjust_ix) {
adjust = true;
cur_adjust_ix += adjust_cycle;
cur_cycle_end =
cur_adjust_ix < total ? datelist[cur_adjust_ix] : datelist.back() + Seconds(1);
}

const auto& date = datelist[i];
_runMoment(date, adjust);
_runMoment(date, cur_cycle_end, adjust);
}

m_need_calculate = false;
Expand All @@ -191,7 +194,7 @@ void Portfolio::run(const KQuery& query, int adjust_cycle, bool force) {
m_tmp_will_remove_sys = SystemWeightList();
}

void Portfolio::_runMoment(const Datetime& date, bool adjust) {
void Portfolio::_runMoment(const Datetime& date, const Datetime& nextCycle, bool adjust) {
// 当前日期小于账户建立日期,直接忽略
HKU_IF_RETURN(date < m_cash_tm->initDatetime(), void());

Expand Down Expand Up @@ -266,47 +269,6 @@ void Portfolio::_runMoment(const Datetime& date, bool adjust) {
funds.cash + funds.market_value, funds.cash, funds.market_value);
}

//----------------------------------------------------------------------
// 开盘时,优先处理上一交易日强制清、减仓失败的系统
//----------------------------------------------------------------------
// for (auto iter = m_failed_sys_map.begin(); iter != m_failed_sys_map.end();) {
// const auto& sys = iter->first;
// Stock stk = sys->getStock();
// if (date > stk.lastDatetime()) {
// // 已退市
// HKU_WARN_IF(trace, "{} has been delisted!", sys->name());
// m_dlist_sys_list.emplace_back(sys);
// m_failed_sys_map.erase(iter++);
// continue;
// }

// auto tr = sys->sellForceOnOpen(date, iter->second, PART_PORTFOLIO);
// if (!tr.isNull()) {
// HKU_INFO_IF(trace, "[PF] Process pre-failed sys: {}", tr);
// m_tm->addTradeRecord(tr);

// // 卖出后,尝试将资金取出转移至影子总账户
// TMPtr sub_tm = sys->getTM();
// auto sub_cash = sub_tm->currentCash();
// if (sub_cash > 0.0 && sub_tm->checkout(date, sub_cash)) {
// m_cash_tm->checkin(date, sub_cash);
// }

// m_failed_sys_map.erase(iter++);
// continue;

// } else {
// // 如果实际已没有持仓,则将其从失败列表中移除
// PositionRecord position = sys->getTM()->getPosition(date, sys->getStock());
// if (position.number <= 0.0) {
// m_failed_sys_map.erase(iter++);
// continue;
// }
// }

// ++iter;
// }

//----------------------------------------------------------------------
// 开盘时,优先处理上一交易日遗留的延迟调仓卖出的系统
//----------------------------------------------------------------------
Expand All @@ -330,51 +292,12 @@ void Portfolio::_runMoment(const Datetime& date, bool adjust) {
PositionRecord position = sys.sys->getTM()->getPosition(date, sys.sys->getStock());
if (position.number > 0.0) {
tmp_continue_adjust_sys_list.emplace_back(sys);
// m_failed_sys_map[sys.sys] = sys.weight;
}
}
}

m_delay_adjust_sys_list.swap(tmp_continue_adjust_sys_list);

//---------------------------------------------------------------
// 遍历当前运行中的子系统,如果已没有分配资金和持仓,则回收
//---------------------------------------------------------------
#if 0
m_tmp_will_remove_sys.clear();
for (auto& running_sys : m_running_sys_set) {
Stock stock = running_sys->getStock();
TMPtr sub_tm = running_sys->getTM();
PositionRecord position = sub_tm->getPosition(date, stock);
price_t cash = sub_tm->currentCash();

price_t min_cash = 1.0;
KRecord krecord = stock.getKRecord(date);
if (krecord.isValid()) {
min_cash = krecord.openPrice * stock.minTradeNumber();
}

// 如果系统的剩余资金小于交易一手的资金,则回收资金??? TODO 放到 AF 中进行处理不足一手的
if (cash != 0 && cash <= min_cash) {
sub_tm->checkout(date, cash);
m_cash_tm->checkin(date, cash);
HKU_INFO_IF(trace, "Recycle cash ({:<.2f}) from {}, current cash: {}", cash,
running_sys->name(), m_cash_tm->currentCash());
// 如果已经没有持仓,则回收
if (position.number <= 0.0) {
m_tmp_will_remove_sys.emplace_back(running_sys, 0.);
HKU_INFO_IF(trace, "[PF] Recycle running sys: {}", running_sys->name());
}
}
}

// 依据待移除列表将系统从运行中系统列表里删除
for (auto& sub_sys : m_tmp_will_remove_sys) {
HKU_INFO_IF(trace, "Recycling system {}", sub_sys.sys->name());
m_running_sys_set.erase(sub_sys.sys);
}
#endif

//---------------------------------------------------
// 调仓日,进行资金分配调整
//---------------------------------------------------
Expand Down Expand Up @@ -437,6 +360,11 @@ void Portfolio::_runMoment(const Datetime& date, bool adjust) {
//----------------------------------------------------------------------------
for (auto& sub_sys : m_running_sys_set) {
HKU_TRACE_IF(trace, "run: {}", sub_sys->name());
if (adjust) {
auto sg = sub_sys->getSG();
sg->startCycle(date, nextCycle);
}

auto tr = sub_sys->runMoment(date);
if (!tr.isNull()) {
HKU_INFO_IF(trace, "[PF] {}", tr);
Expand Down Expand Up @@ -489,12 +417,18 @@ void Portfolio::_runMoment(const Datetime& date, bool adjust) {
stk.market_code(), stk_name, position, funds.market_value, funds.cash,
krecord.openPrice, krecord.closePrice);
#endif
HKU_INFO(
"+------------+------------+------------+--------------+--------------+-------------"
"+-------------+");
if (++count >= 100) {
// clang-format off
HKU_INFO("+------------+------------+------------+--------------+--------------+-------------+-------------+");
count++;
int trace_max_num = getParam<int>("trace_max_num");
if (count >= trace_max_num) {
if (count > trace_max_num) {
HKU_INFO("+ ... ... more +");
HKU_INFO("+------------+------------+------------+--------------+--------------+-------------+-------------+");
}
break;
}
// clang-format on
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class HKU_API Portfolio : public enable_shared_from_this<Portfolio> {
/** 运行前准备 */
void _readyForRun();

void _runMoment(const Datetime& date, bool adjust);
void _runMoment(const Datetime& date, const Datetime& nextCycle, bool adjust);

protected:
string m_name;
Expand All @@ -117,7 +117,6 @@ class HKU_API Portfolio : public enable_shared_from_this<Portfolio> {

// 用于中间计算的临时数据
std::unordered_set<SYSPtr> m_running_sys_set;
std::unordered_map<SYSPtr, double> m_failed_sys_map; // 强制卖出失败的系统集合
SystemList m_dlist_sys_list; // 因证券退市,无法执行买入的系统(资产全部损失)
SystemWeightList m_delay_adjust_sys_list; // 延迟调仓卖出的系统列表
SystemWeightList m_tmp_selected_list;
Expand Down

0 comments on commit 26da56f

Please sign in to comment.