diff --git a/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp b/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp index 54fdbe66..d5653ef4 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp @@ -305,6 +305,17 @@ void Portfolio::_runMoment(const Datetime& date, const Datetime& nextCycle, bool m_delay_adjust_sys_list.swap(tmp_continue_adjust_sys_list); + //--------------------------------------------------- + // 检测当前运行中的系统是否存在延迟卖出信号,并在开盘时有效处理 + //--------------------------------------------------- + for (auto& sys : m_running_sys_set) { + auto tr = sys->pfProcessDelaySellRequest(date); + if (!tr.isNull()) { + HKU_INFO_IF(trace, "[PF] sell delay {}", tr); + m_tm->addTradeRecord(tr); + } + } + //--------------------------------------------------- // 调仓日,进行资金分配调整 //--------------------------------------------------- @@ -312,10 +323,10 @@ void Portfolio::_runMoment(const Datetime& date, const Datetime& nextCycle, bool // 从选股策略获取选中的系统列表 m_tmp_selected_list = m_se->getSelected(date); - // 如果选中的系统不在已有列表中, 则先清除其延迟操作,防止在调仓日出现未来信号 + // 如果选中的系统不在已有列表中, 则先清除其延迟买入操作,防止在调仓日出现未来信号 for (auto& sys : m_tmp_selected_list) { if (m_running_sys_set.find(sys.sys) == m_running_sys_set.end()) { - sys.sys->clearDelayRequest(); + sys.sys->clearDelayBuyRequest(); } } diff --git a/hikyuu_cpp/hikyuu/trade_sys/system/System.cpp b/hikyuu_cpp/hikyuu/trade_sys/system/System.cpp index ebcb7e45..bef25c41 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/system/System.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/system/System.cpp @@ -406,11 +406,12 @@ void System::run(const KData& kdata, bool reset, bool resetAll) { m_calculated = true; } -void System::clearDelayRequest() { +void System::clearDelayBuyRequest() { m_buyRequest.clear(); - m_sellRequest.clear(); - m_sellShortRequest.clear(); - m_buyShortRequest.clear(); +} + +bool System::haveDelaySellRequest() const { + return m_sellRequest.valid; } TradeRecord System::runMoment(const Datetime& datetime) { @@ -767,12 +768,16 @@ TradeRecord System::_sellForce(const Datetime& date, double num, Part from, bool } TradeRecord System::_sell(const KRecord& today, const KRecord& src_today, Part from) { + bool trace = getParam("trace"); TradeRecord result; if (getParam("sell_delay")) { _submitSellRequest(today, src_today, from); + HKU_INFO_IF(trace, "[{}] will be delay to sell", name()); return result; } else { - return _sellNow(today, src_today, from); + result = _sellNow(today, src_today, from); + HKU_INFO_IF(trace, "[{}] sell now: {}", name(), result); + return result; } } @@ -817,6 +822,9 @@ TradeRecord System::_sellNow(const KRecord& today, const KRecord& src_today, Par } TradeRecord System::_sellDelay(const KRecord& today, const KRecord& src_today) { + bool trace = getParam("trace"); + HKU_INFO_IF(trace, "[{}] process _sellDelay request", name()); + TradeRecord result; if (today.highPrice == today.lowPrice && !getParam("can_trade_when_high_eq_low")) { // 无法执行,保留卖出请求,继续延迟至下一时刻 @@ -1175,6 +1183,15 @@ TradeRecord System::_processRequest(const KRecord& today, const KRecord& src_tod return TradeRecord(); } +TradeRecord System::pfProcessDelaySellRequest(const Datetime& date) { + HKU_IF_RETURN(!m_sellRequest.valid, TradeRecord()); + size_t pos = m_kdata.getPos(date); + HKU_IF_RETURN(pos == Null(), TradeRecord()); + KRecord today = m_kdata.getKRecord(pos); + KRecord src_today = m_src_kdata.getKRecord(pos); + return _sellDelay(today, src_today); +} + price_t System::_getStoplossPrice(const KRecord& today, const KRecord& src_today, price_t price) { HKU_IF_RETURN(!m_st, 0.0); HKU_IF_RETURN(today.highPrice == today.lowPrice, src_today.lowPrice); diff --git a/hikyuu_cpp/hikyuu/trade_sys/system/System.h b/hikyuu_cpp/hikyuu/trade_sys/system/System.h index fe949ae9..3ff20618 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/system/System.h +++ b/hikyuu_cpp/hikyuu/trade_sys/system/System.h @@ -25,12 +25,17 @@ namespace hku { +class HKU_API Portfolio; +class HKU_API AllocateFundsBase; + /** * 交易系统基类 * @ingroup System */ class HKU_API System { PARAMETER_SUPPORT_WITH_CHECK + friend class HKU_API Portfolio; + friend class HKU_API AllocateFundsBase; public: /** 默认构造函数 */ @@ -200,12 +205,6 @@ public: */ TradeRecord runMoment(const Datetime& datetime); - // 清除已有的交易请求,供Portfolio使用 - void clearDelayRequest(); - - // 当前是否存在延迟的操作请求,供Portfolio - bool haveDelayRequest() const; - // 运行前准备工作, 失败将抛出异常 void readyForRun(); @@ -213,6 +212,12 @@ public: return _sell(today, src_today, from); } + // 由各个相关组件调用,用于组件参数变化时通知 sys,以便重算 + void partChangedNotify() { + m_calculated = false; + } + +private: // 强制以开盘价卖出,仅供 PF/AF 内部调用 TradeRecord sellForceOnOpen(const Datetime& date, double num, Part from) { HKU_ASSERT(from == PART_ALLOCATEFUNDS || from == PART_PORTFOLIO); @@ -225,10 +230,14 @@ public: return _sellForce(date, num, from, false); } - // 由各个相关组件调用,用于组件参数变化时通知 sys,以便重算 - void partChangedNotify() { - m_calculated = false; - } + // 清除已有的交易请求,供Portfolio使用 + void clearDelayBuyRequest(); + + // 当前是否存在延迟的操作请求,供Portfolio + bool haveDelaySellRequest() const; + + // 处理延迟买入请求,仅供 PF 调用 + TradeRecord pfProcessDelaySellRequest(const Datetime& date); private: bool _environmentIsValid(const Datetime& datetime); diff --git a/hikyuu_cpp/hikyuu/trade_sys/system/SystemPart.cpp b/hikyuu_cpp/hikyuu/trade_sys/system/SystemPart.cpp index 5c6668e2..57ed092f 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/system/SystemPart.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/system/SystemPart.cpp @@ -30,6 +30,8 @@ string HKU_API getSystemPartName(int part) { return "SP"; case PART_ALLOCATEFUNDS: return "AF"; + case PART_PORTFOLIO: + return "PF"; default: return "--"; } @@ -47,6 +49,7 @@ SystemPart HKU_API getSystemPartEnum(const string& arg) { HKU_IF_RETURN("SP" == name, PART_SLIPPAGE); HKU_IF_RETURN("MM" == name, PART_MONEYMANAGER); HKU_IF_RETURN("AF" == name, PART_ALLOCATEFUNDS); + HKU_IF_RETURN("PF" == name, PART_PORTFOLIO); return PART_INVALID; }