Merge pull request #202 from fasiondog/feature/param

策略组件参数检查与更新优化; fixed system 止盈延迟参数未生效
This commit is contained in:
fasiondog 2024-03-25 22:34:23 +08:00 committed by GitHub
commit f6c8869ea5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
76 changed files with 350 additions and 111 deletions

View File

@ -50,7 +50,7 @@
.. py:function:: MM_FixedCapital([capital = 10000.0])
固定资本资金管理策略
固定资本资金管理策略, 即控制每次买入投入的总资金
:param float capital: 固定资本单位
:return: 资金管理策略实例

View File

@ -31,6 +31,9 @@ TradeCostBase::TradeCostBase(const string& name) : m_name(name) {}
TradeCostBase::~TradeCostBase() {}
void TradeCostBase::baseCheckParam(const string& name) const {}
void TradeCostBase::paramChanged() {}
TradeCostPtr TradeCostBase::clone() {
TradeCostPtr result = _clone();
TradeCostBase* p = result.get();

View File

@ -20,7 +20,7 @@ namespace hku {
* @ingroup TradeCost
*/
class HKU_API TradeCostBase {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
TradeCostBase(const string& name);

View File

@ -23,6 +23,18 @@ FixedA2015TradeCost::FixedA2015TradeCost() : TradeCostBase("TC_FixedA2015") {
FixedA2015TradeCost::~FixedA2015TradeCost() {}
void FixedA2015TradeCost::_checkParam(const string& name) const {
if ("commission" == name) {
HKU_ASSERT(getParam<price_t>("commission") >= 0.0);
} else if ("lowest_commission" == name) {
HKU_ASSERT(getParam<price_t>("lowest_commission") >= 0.0);
} else if ("stamptax" == name) {
HKU_ASSERT(getParam<price_t>("stamptax") >= 0.0);
} else if ("transferfee" == name) {
HKU_ASSERT(getParam<price_t>("transferfee") >= 0.0);
}
}
CostRecord FixedA2015TradeCost::getBuyCost(const Datetime& datetime, const Stock& stock,
price_t price, double num) const {
CostRecord result;

View File

@ -20,6 +20,8 @@ public:
FixedA2015TradeCost();
virtual ~FixedA2015TradeCost();
virtual void _checkParam(const string& name) const override;
/**
*
* @param datetime

View File

@ -23,6 +23,18 @@ FixedA2017TradeCost::FixedA2017TradeCost() : TradeCostBase("TC_FixedA2017") {
FixedA2017TradeCost::~FixedA2017TradeCost() {}
void FixedA2017TradeCost::_checkParam(const string& name) const {
if ("commission" == name) {
HKU_ASSERT(getParam<price_t>("commission") >= 0.0);
} else if ("lowest_commission" == name) {
HKU_ASSERT(getParam<price_t>("lowest_commission") >= 0.0);
} else if ("stamptax" == name) {
HKU_ASSERT(getParam<price_t>("stamptax") >= 0.0);
} else if ("transferfee" == name) {
HKU_ASSERT(getParam<price_t>("transferfee") >= 0.0);
}
}
CostRecord FixedA2017TradeCost::getBuyCost(const Datetime& datetime, const Stock& stock,
price_t price, double num) const {
CostRecord result;

View File

@ -23,6 +23,8 @@ public:
FixedA2017TradeCost();
virtual ~FixedA2017TradeCost();
virtual void _checkParam(const string& name) const override;
/**
*
* @param datetime

View File

@ -35,6 +35,20 @@ FixedATradeCost::FixedATradeCost(price_t commission, price_t lowestCommission, p
FixedATradeCost::~FixedATradeCost() {}
void FixedATradeCost::_checkParam(const string& name) const {
if ("commission" == name) {
HKU_ASSERT(getParam<price_t>("commission") >= 0.0);
} else if ("lowest_commission" == name) {
HKU_ASSERT(getParam<price_t>("lowest_commission") >= 0.0);
} else if ("stamptax" == name) {
HKU_ASSERT(getParam<price_t>("stamptax") >= 0.0);
} else if ("transferfee" == name) {
HKU_ASSERT(getParam<price_t>("transferfee") >= 0.0);
} else if ("lowest_transferfee" == name) {
HKU_ASSERT(getParam<price_t>("lowest_transferfee") >= 0.0);
}
}
CostRecord FixedATradeCost::getBuyCost(const Datetime& datetime, const Stock& stock, price_t price,
double num) const {
CostRecord result;

View File

@ -56,6 +56,8 @@ public:
price_t transferfee, price_t lowestTransferfee);
virtual ~FixedATradeCost();
virtual void _checkParam(const string& name) const override;
/**
*
* @param datetime

View File

@ -56,6 +56,9 @@ AllocateFundsBase::AllocateFundsBase(const string& name)
AllocateFundsBase::~AllocateFundsBase() {}
void AllocateFundsBase::baseCheckParam(const string& name) const {}
void AllocateFundsBase::paramChanged() {}
void AllocateFundsBase::reset() {
// 参数检查
double default_reserve_percent = getParam<double>("default_reserve_percent");

View File

@ -20,7 +20,7 @@ namespace hku {
* @ingroup AllocateFunds
*/
class HKU_API AllocateFundsBase : public enable_shared_from_this<AllocateFundsBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
/** 默认构造函数 */

View File

@ -19,6 +19,13 @@ FixedWeightAllocateFunds::FixedWeightAllocateFunds() : AllocateFundsBase("AF_Fix
FixedWeightAllocateFunds::~FixedWeightAllocateFunds() {}
void FixedWeightAllocateFunds::_checkParam(const string& name) const {
if ("weight" == name) {
double weight = getParam<double>("weight");
HKU_ASSERT(weight > 0.0 && weight <= 1.);
}
}
SystemWeightList FixedWeightAllocateFunds ::_allocateWeight(const Datetime& date,
const SystemWeightList& se_list) {
SystemWeightList result;

View File

@ -20,6 +20,7 @@ class FixedWeightAllocateFunds : public AllocateFundsBase {
public:
FixedWeightAllocateFunds();
virtual ~FixedWeightAllocateFunds();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -30,6 +30,9 @@ ConditionBase::ConditionBase(const string& name) : m_name(name) {}
ConditionBase::~ConditionBase() {}
void ConditionBase::baseCheckParam(const string& name) const {}
void ConditionBase::paramChanged() {}
void ConditionBase::reset() {
m_kdata = Null<KData>();
m_tm.reset();

View File

@ -22,7 +22,7 @@ namespace hku {
* @ingroup Condition
*/
class HKU_API ConditionBase : public enable_shared_from_this<ConditionBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
ConditionBase();

View File

@ -29,6 +29,9 @@ EnvironmentBase::EnvironmentBase(const string& name) : m_name(name) {}
EnvironmentBase::~EnvironmentBase() {}
void EnvironmentBase::baseCheckParam(const string& name) const {}
void EnvironmentBase::paramChanged() {}
void EnvironmentBase::reset() {
std::unique_lock<std::shared_mutex> lock(m_mutex);
m_query = Null<KQuery>();

View File

@ -22,7 +22,7 @@ namespace hku {
* @ingroup Environment
*/
class HKU_API EnvironmentBase : public enable_shared_from_this<EnvironmentBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
EnvironmentBase();

View File

@ -24,6 +24,14 @@ BoolEnvironment::BoolEnvironment(const Indicator& ind) : EnvironmentBase("EV_Boo
BoolEnvironment::~BoolEnvironment() {}
void BoolEnvironment::_checkParam(const string& name) const {
if ("market" == name) {
string market = getParam<string>(name);
auto market_info = StockManager::instance().getMarketInfo(name);
HKU_CHECK(market_info == Null<MarketInfo>(), "Invalid market: {}", market);
}
}
EnvironmentPtr BoolEnvironment::_clone() {
return make_shared<BoolEnvironment>(m_ind.clone());
}

View File

@ -18,6 +18,7 @@ public:
explicit BoolEnvironment(const Indicator& ind);
virtual ~BoolEnvironment();
virtual void _checkParam(const string& name) const override;
virtual void _calculate() override;
virtual EnvironmentPtr _clone() override;

View File

@ -26,6 +26,14 @@ TwoLineEnvironment::TwoLineEnvironment(const Indicator& fast, const Indicator& s
TwoLineEnvironment::~TwoLineEnvironment() {}
void TwoLineEnvironment::_checkParam(const string& name) const {
if ("market" == name) {
string market = getParam<string>(name);
auto market_info = StockManager::instance().getMarketInfo(name);
HKU_CHECK(market_info == Null<MarketInfo>(), "Invalid market: {}", market);
}
}
EnvironmentPtr TwoLineEnvironment::_clone() {
TwoLineEnvironment* ptr = new TwoLineEnvironment;
ptr->m_fast = m_fast.clone();

View File

@ -20,6 +20,7 @@ public:
TwoLineEnvironment(const Indicator& fast, const Indicator& slow);
virtual ~TwoLineEnvironment();
virtual void _checkParam(const string& name) const override;
virtual void _calculate() override;
virtual EnvironmentPtr _clone() override;

View File

@ -102,7 +102,7 @@ void MultiFactorBase::initParam() {
setParam<double>("zscore_nsigma", 3.0);
}
void MultiFactorBase::checkParam(const string& name) const {
void MultiFactorBase::baseCheckParam(const string& name) const {
if ("ic_n" == name) {
HKU_ASSERT(getParam<int>("ic_n") >= 1);
} else if ("zscore_nsigma" == name) {

View File

@ -29,8 +29,7 @@ ICIRMultiFactor::ICIRMultiFactor(const vector<Indicator>& inds, const StockList&
checkParam("ic_rolling_n");
}
void ICIRMultiFactor::checkParam(const string& name) const {
MultiFactorBase::checkParam(name);
void ICIRMultiFactor::_checkParam(const string& name) const {
if ("ic_rolling_n" == name) {
HKU_ASSERT(getParam<int>("ic_rolling_n") >= 1);
}

View File

@ -21,7 +21,7 @@ public:
const Stock& ref_stk, int ic_n, int ic_rolling_n);
virtual ~ICIRMultiFactor() = default;
virtual void checkParam(const string& name) const override;
virtual void _checkParam(const string& name) const override;
};
} // namespace hku

View File

@ -28,8 +28,7 @@ ICMultiFactor::ICMultiFactor(const IndicatorList& inds, const StockList& stks, c
checkParam("ic_rolling_n");
}
void ICMultiFactor::checkParam(const string& name) const {
MultiFactorBase::checkParam(name);
void ICMultiFactor::_checkParam(const string& name) const {
if ("ic_rolling_n" == name) {
HKU_ASSERT(getParam<int>("ic_rolling_n") >= 1);
}

View File

@ -21,7 +21,7 @@ public:
const Stock& ref_stk, int ic_n, int ic_rolling_n);
virtual ~ICMultiFactor() = default;
virtual void checkParam(const string& name) const override;
virtual void _checkParam(const string& name) const override;
};
} // namespace hku

View File

@ -40,6 +40,14 @@ MoneyManagerBase::MoneyManagerBase(const string& name) : m_name(name) {
MoneyManagerBase::~MoneyManagerBase() {}
void MoneyManagerBase::baseCheckParam(const string& name) const {
if ("max-stock" == name) {
HKU_ASSERT(getParam<int>("max-stock") >= 1);
}
}
void MoneyManagerBase::paramChanged() {}
void MoneyManagerBase::buyNotify(const TradeRecord&) {}
void MoneyManagerBase::sellNotify(const TradeRecord&) {}
@ -110,21 +118,16 @@ double MoneyManagerBase::getBuyNumber(const Datetime& datetime, const Stock& sto
double n = _getBuyNumber(datetime, stock, price, risk, from);
double min_trade = stock.minTradeNumber();
if (n < min_trade) {
HKU_TRACE("Ignore! Is less than the minimum number of transactions({}<{}) {}", n, min_trade,
stock.market_code());
return 0;
}
HKU_TRACE_IF_RETURN(n < min_trade, 0.0,
"Ignore! Is less than the minimum number of transactions({}<{}) {}", n,
min_trade, stock.market_code());
// 转换为最小交易量的整数倍
n = long(n / min_trade) * min_trade;
double max_trade = stock.maxTradeNumber();
n = int64_t(n / min_trade) * min_trade;
if (n > max_trade) {
n = max_trade;
HKU_INFO("Over stock.maxTradeNumber({})!", max_trade);
}
double max_trade = stock.maxTradeNumber();
HKU_WARN_IF_RETURN(n > max_trade, max_trade,
"Over stock.maxTradeNumber({}), will use maxTradeNumber", max_trade);
// 在现金不足时,自动补充存入现金
if (getParam<bool>("auto-checkin")) {

View File

@ -20,7 +20,7 @@ namespace hku {
* @ingroup MoneyManager
*/
class HKU_API MoneyManagerBase : public enable_shared_from_this<MoneyManagerBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
MoneyManagerBase();

View File

@ -19,6 +19,13 @@ FixedCapitalMoneyManager::FixedCapitalMoneyManager() : MoneyManagerBase("MM_Fixe
FixedCapitalMoneyManager::~FixedCapitalMoneyManager() {}
void FixedCapitalMoneyManager::_checkParam(const string& name) const {
if ("capital" == name) {
double capital = getParam<double>("capital");
HKU_ASSERT(capital > 0.0);
}
}
double FixedCapitalMoneyManager ::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
double capital = getParam<double>("capital");

View File

@ -20,6 +20,7 @@ class FixedCapitalMoneyManager : public MoneyManagerBase {
public:
FixedCapitalMoneyManager();
virtual ~FixedCapitalMoneyManager();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -19,6 +19,13 @@ FixedCountMoneyManager::FixedCountMoneyManager() : MoneyManagerBase("MM_FixedCou
FixedCountMoneyManager::~FixedCountMoneyManager() {}
void FixedCountMoneyManager::_checkParam(const string& name) const {
if ("n" == name) {
double n = getParam<double>("n");
HKU_ASSERT(n > 0.0);
}
}
double FixedCountMoneyManager ::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
return getParam<double>("n");

View File

@ -31,6 +31,7 @@ class FixedCountMoneyManager : public MoneyManagerBase {
public:
FixedCountMoneyManager();
virtual ~FixedCountMoneyManager();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -19,11 +19,16 @@ FixedPercentMoneyManager::FixedPercentMoneyManager() : MoneyManagerBase("MM_Fixe
FixedPercentMoneyManager::~FixedPercentMoneyManager() {}
void FixedPercentMoneyManager::_checkParam(const string& name) const {
if ("p" == name) {
double p = getParam<double>("p");
HKU_ASSERT(p > 0 && p <= 1.0);
}
}
double FixedPercentMoneyManager ::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
double p = getParam<double>("p");
HKU_ERROR_IF_RETURN(p <= 0.0 || p > 1.0, 0.0, "Error param (p = {:<.4f})", p);
HKU_ERROR_IF_RETURN(risk == 0.0, 0.0, "risk is zero!");
return m_tm->cash(datetime, m_query.kType()) * p / risk;
}

View File

@ -26,6 +26,7 @@ class HKU_API FixedPercentMoneyManager : public MoneyManagerBase {
public:
FixedPercentMoneyManager();
virtual ~FixedPercentMoneyManager();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -20,6 +20,13 @@ FixedRatioMoneyManager::FixedRatioMoneyManager()
FixedRatioMoneyManager::~FixedRatioMoneyManager() {}
void FixedRatioMoneyManager::_checkParam(const string& name) const {
if ("delta" == name) {
double delta = getParam<double>("delta");
HKU_ASSERT(delta > 0.0);
}
}
void FixedRatioMoneyManager::_reset() {
m_current_num = 1;
m_pre_cash = 0.0;

View File

@ -18,6 +18,7 @@ public:
FixedRatioMoneyManager();
virtual ~FixedRatioMoneyManager();
virtual void _checkParam(const string& name) const override;
virtual void _reset() override;
virtual MoneyManagerPtr _clone() override;
virtual double _getBuyNumber(const Datetime& datetime, const Stock& stock, price_t price,

View File

@ -19,6 +19,13 @@ FixedRiskMoneyManager::FixedRiskMoneyManager() : MoneyManagerBase("MM_FixedRisk"
FixedRiskMoneyManager::~FixedRiskMoneyManager() {}
void FixedRiskMoneyManager::_checkParam(const string& name) const {
if ("risk" == name) {
double risk = getParam<double>("risk");
HKU_ASSERT(risk > 0.0);
}
}
double FixedRiskMoneyManager ::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
return getParam<double>("risk") / risk;

View File

@ -20,6 +20,7 @@ class FixedRiskMoneyManager : public MoneyManagerBase {
public:
FixedRiskMoneyManager();
virtual ~FixedRiskMoneyManager();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -19,6 +19,13 @@ FixedUnitsMoneyManager::FixedUnitsMoneyManager() : MoneyManagerBase("MM_FixedUni
FixedUnitsMoneyManager::~FixedUnitsMoneyManager() {}
void FixedUnitsMoneyManager::_checkParam(const string& name) const {
if ("n" == name) {
int n = getParam<int>("n");
HKU_ASSERT(n > 0);
}
}
double FixedUnitsMoneyManager ::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
int n = getParam<int>("n");

View File

@ -20,6 +20,7 @@ class FixedUnitsMoneyManager : public MoneyManagerBase {
public:
FixedUnitsMoneyManager();
virtual ~FixedUnitsMoneyManager();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -21,8 +21,18 @@ WilliamsFixedRiskMoneyManager::WilliamsFixedRiskMoneyManager()
WilliamsFixedRiskMoneyManager::~WilliamsFixedRiskMoneyManager() {}
double WilliamsFixedRiskMoneyManager ::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
void WilliamsFixedRiskMoneyManager::_checkParam(const string& name) const {
if ("p" == name) {
double p = getParam<double>("p");
HKU_ASSERT(p > 0.0);
} else if ("max_loss" == name) {
price_t max_loss = getParam<price_t>("max_loss");
HKU_ASSERT(max_loss > 0.0);
}
}
double WilliamsFixedRiskMoneyManager::_getBuyNumber(const Datetime& datetime, const Stock& stock,
price_t price, price_t risk, SystemPart from) {
price_t max_loss = getParam<price_t>("max_loss");
HKU_WARN_IF_RETURN(max_loss <= 0.0, 0.0, "max_loss is zero!");
return m_tm->cash(datetime, m_query.kType()) * getParam<double>("p") / max_loss;

View File

@ -20,6 +20,7 @@ class WilliamsFixedRiskMoneyManager : public MoneyManagerBase {
public:
WilliamsFixedRiskMoneyManager();
virtual ~WilliamsFixedRiskMoneyManager();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -29,6 +29,9 @@ ProfitGoalBase::ProfitGoalBase(const string& name) : m_name(name) {}
ProfitGoalBase::~ProfitGoalBase() {}
void ProfitGoalBase::baseCheckParam(const string& name) const {}
void ProfitGoalBase::paramChanged() {}
void ProfitGoalBase::reset() {
m_kdata = Null<KData>();
m_tm.reset();

View File

@ -21,7 +21,7 @@ namespace hku {
* @ingroup ProfitGoal
*/
class HKU_API ProfitGoalBase : public enable_shared_from_this<ProfitGoalBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
ProfitGoalBase();

View File

@ -19,11 +19,16 @@ FixedHoldDays::FixedHoldDays() : ProfitGoalBase("PG_FixedHoldDays") {
FixedHoldDays::~FixedHoldDays() {}
void FixedHoldDays::_checkParam(const string& name) const {
if ("days" == name) {
int days = getParam<int>(name);
HKU_ASSERT(days > 0);
}
}
void FixedHoldDays::_calculate() {}
price_t FixedHoldDays::getGoal(const Datetime& datetime, price_t price) {
HKU_WARN_IF_RETURN(getParam<int>("days") <= 0, 0.0, "param days <= 0! Are you sure?");
Stock stk = m_kdata.getStock();
PositionRecord position = m_tm->getPosition(datetime, stk);
Datetime take_date = position.takeDatetime;

View File

@ -20,6 +20,8 @@ class FixedHoldDays : public ProfitGoalBase {
public:
FixedHoldDays();
virtual ~FixedHoldDays();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -21,6 +21,13 @@ FixedPercentProfitGoal::~FixedPercentProfitGoal() {}
void FixedPercentProfitGoal::_calculate() {}
void FixedPercentProfitGoal::_checkParam(const string& name) const {
if ("p" == name) {
double p = getParam<double>(name);
HKU_ASSERT(p > 0.0);
}
}
price_t FixedPercentProfitGoal::getGoal(const Datetime& datetime, price_t price) {
Stock stock = getTO().getStock();
PositionRecord position = getTM()->getPosition(datetime, stock);

View File

@ -20,6 +20,7 @@ class FixedPercentProfitGoal : public ProfitGoalBase {
public:
FixedPercentProfitGoal();
virtual ~FixedPercentProfitGoal();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -36,6 +36,9 @@ SelectorBase::SelectorBase(const string& name) : m_name(name) {
SelectorBase::~SelectorBase() {}
void SelectorBase::baseCheckParam(const string& name) const {}
void SelectorBase::paramChanged() {}
void SelectorBase::removeAll() {
m_pro_sys_list = SystemList();
m_real_sys_list = SystemList();

View File

@ -24,7 +24,7 @@ class HKU_API Portfolio;
* @ingroup Selector
*/
class HKU_API SelectorBase : public enable_shared_from_this<SelectorBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
/** 默认构造函数 */

View File

@ -36,6 +36,9 @@ SignalBase::SignalBase(const string& name) : m_name(name), m_hold_long(false), m
SignalBase::~SignalBase() {}
void SignalBase::baseCheckParam(const string& name) const {}
void SignalBase::paramChanged() {}
SignalPtr SignalBase::clone() {
SignalPtr p;
try {

View File

@ -22,7 +22,7 @@ namespace hku {
* @ingroup Signal
*/
class HKU_API SignalBase : public enable_shared_from_this<SignalBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
SignalBase();

View File

@ -17,7 +17,7 @@ BandSignal::BandSignal() : SignalBase("SG_Band") {}
BandSignal::BandSignal(const Indicator& ind, price_t lower, price_t upper)
: SignalBase("SG_Band"), m_ind(ind), m_lower(lower), m_upper(upper) {
HKU_ERROR_IF(lower > upper, "BandSignal: lower track is greater than upper track");
HKU_CHECK(lower > upper, "BandSignal: lower track is greater than upper track");
}
BandSignal::~BandSignal() {}

View File

@ -1,12 +0,0 @@
/*
* Copyright (c) 2024 hikyuu.org
*
* Created on: 2024-03-12
* Author: fasiondog
*/
#pragma once
#include "../SignalBase.h"
namespace hku {}

View File

@ -28,6 +28,15 @@ SingleSignal::SingleSignal(const Indicator& ind) : SignalBase("SG_Single"), m_in
SingleSignal::~SingleSignal() {}
void SingleSignal::_checkParam(const string& name) const {
if ("filter_n" == name) {
HKU_ASSERT(getParam<int>("filter_n") >= 3);
} else if ("filter_p" == name) {
double filter_p = getParam<double>(name);
HKU_ASSERT(filter_p > 0.0 && filter_p < 1.0);
}
}
SignalPtr SingleSignal::_clone() {
SingleSignal* p = new SingleSignal();
p->m_ind = m_ind.clone();

View File

@ -20,6 +20,7 @@ public:
explicit SingleSignal(const Indicator& ind);
virtual ~SingleSignal();
virtual void _checkParam(const string& name) const override;
virtual SignalPtr _clone() override;
virtual void _calculate() override;

View File

@ -31,6 +31,15 @@ SingleSignal2::SingleSignal2(const Indicator& ind) : SignalBase("SG_Single2"), m
SingleSignal2::~SingleSignal2() {}
void SingleSignal2::_checkParam(const string& name) const {
if ("filter_n" == name) {
HKU_ASSERT(getParam<int>("filter_n") >= 3);
} else if ("filter_p" == name) {
double filter_p = getParam<double>(name);
HKU_ASSERT(filter_p > 0.0 && filter_p < 1.0);
}
}
SignalPtr SingleSignal2::_clone() {
SingleSignal2* p = new SingleSignal2();
p->m_ind = m_ind.clone();

View File

@ -20,6 +20,7 @@ public:
explicit SingleSignal2(const Indicator&);
virtual ~SingleSignal2();
virtual void _checkParam(const string& name) const override;
virtual SignalPtr _clone() override;
virtual void _calculate() override;

View File

@ -27,6 +27,9 @@ SlippageBase::SlippageBase() : m_name("SlippageBase") {}
SlippageBase::SlippageBase(const string& name) : m_name(name) {}
void SlippageBase::baseCheckParam(const string& name) const {}
void SlippageBase::paramChanged() {}
void SlippageBase::reset() {
m_kdata = Null<KData>();
_reset();

View File

@ -19,7 +19,7 @@ namespace hku {
* @ingroup Slippage
*/
class HKU_API SlippageBase : public enable_shared_from_this<SlippageBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
SlippageBase();

View File

@ -19,6 +19,13 @@ FixedPercentSlippage::FixedPercentSlippage() : SlippageBase("FixedPercent") {
FixedPercentSlippage::~FixedPercentSlippage() {}
void FixedPercentSlippage::_checkParam(const string& name) const {
if ("p" == name) {
double p = getParam<double>(name);
HKU_ASSERT(p >= 0.0 && p < 1.0);
}
}
price_t FixedPercentSlippage ::getRealBuyPrice(const Datetime& datetime, price_t price) {
return price * (1 + getParam<double>("p"));
}

View File

@ -20,6 +20,7 @@ class FixedPercentSlippage : public SlippageBase {
public:
FixedPercentSlippage();
virtual ~FixedPercentSlippage();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -19,6 +19,12 @@ FixedValueSlippage::FixedValueSlippage() {
FixedValueSlippage::~FixedValueSlippage() {}
void FixedValueSlippage::_checkParam(const string& name) const {
if ("p" == name) {
HKU_ASSERT(getParam<double>(name) >= 0.0);
}
}
price_t FixedValueSlippage ::getRealBuyPrice(const Datetime& datetime, price_t price) {
return price + getParam<double>("value");
}

View File

@ -20,6 +20,7 @@ class FixedValueSlippage : public SlippageBase {
public:
FixedValueSlippage();
virtual ~FixedValueSlippage();
virtual void _checkParam(const string& name) const override;
};
} /* namespace hku */

View File

@ -29,6 +29,9 @@ StoplossBase::StoplossBase(const string& name) : m_name(name) {}
StoplossBase::~StoplossBase() {}
void StoplossBase::baseCheckParam(const string& name) const {}
void StoplossBase::paramChanged() {}
void StoplossBase::reset() {
m_kdata = Null<KData>();
m_tm.reset();

View File

@ -21,7 +21,7 @@ namespace hku {
* @ingroup Stoploss
*/
class HKU_API StoplossBase : public enable_shared_from_this<StoplossBase> {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
StoplossBase();

View File

@ -19,6 +19,13 @@ FixedPercentStoploss::FixedPercentStoploss() : StoplossBase("ST_FixedPercent") {
FixedPercentStoploss::~FixedPercentStoploss() {}
void FixedPercentStoploss::_checkParam(const string& name) const {
if ("p" == name) {
double p = getParam<double>("p");
HKU_ASSERT(p > 0.0 && p <= 1.0);
}
}
price_t FixedPercentStoploss ::getPrice(const Datetime& datetime, price_t price) {
Stock stock = m_kdata.getStock();
int precision = stock.isNull() ? 2 : stock.precision();

View File

@ -23,6 +23,7 @@ class FixedPercentStoploss : public StoplossBase {
public:
FixedPercentStoploss();
virtual ~FixedPercentStoploss();
virtual void _checkParam(const string& name) const;
};
} /* namespace hku */

View File

@ -21,10 +21,19 @@ IndicatorStoploss::IndicatorStoploss() : StoplossBase("IndicatorStoploss") {
IndicatorStoploss::IndicatorStoploss(const Indicator& op, const string& kdata_part)
: StoplossBase("IndicatorStoploss"), m_op(op) {
setParam<string>("kpart", "CLOSE");
checkParam("kpart");
}
IndicatorStoploss::~IndicatorStoploss() {}
void IndicatorStoploss::_checkParam(const string& name) const {
if ("kpart" == name) {
string kpart = getParam<string>("kpart");
HKU_ASSERT("CLOSE" == kpart || "OPEN" == kpart || "HIGH" == kpart || "LOW" == kpart ||
"AMO" == kpart || "VOL" == kpart);
}
}
price_t IndicatorStoploss::getPrice(const Datetime& datetime, price_t price) {
return m_result.count(datetime) ? m_result[datetime] : 0.0;
}

View File

@ -16,9 +16,10 @@ namespace hku {
class IndicatorStoploss : public StoplossBase {
public:
IndicatorStoploss(); //仅用于序列化默认构造函数
IndicatorStoploss(); // 仅用于序列化默认构造函数
IndicatorStoploss(const Indicator& op, const string& kdata_part);
virtual ~IndicatorStoploss();
virtual void _checkParam(const string& name) const;
virtual price_t getPrice(const Datetime& datetime, price_t price) override;
virtual void _reset() override;
@ -30,7 +31,7 @@ private:
map<Datetime, price_t> m_result;
//========================================
//序列化支持
// 序列化支持
//========================================
#if HKU_SUPPORT_SERIALIZATION
private:

View File

@ -33,7 +33,7 @@ HKU_API std::ostream& operator<<(std::ostream& os, const SystemPtr& sys) {
System::System()
: m_name("SYS_Simple"),
m_part_changed(true),
m_calculated(false),
m_pre_ev_valid(true), // must true
m_pre_cn_valid(true), // must true
m_buy_days(0),
@ -45,7 +45,7 @@ System::System()
System::System(const string& name)
: m_name(name),
m_part_changed(true),
m_calculated(false),
m_pre_ev_valid(true),
m_pre_cn_valid(true),
m_buy_days(0),
@ -69,7 +69,7 @@ System::System(const TradeManagerPtr& tm, const MoneyManagerPtr& mm, const Envir
m_pg(pg),
m_sp(sp),
m_name(name),
m_part_changed(true),
m_calculated(false),
m_pre_ev_valid(true),
m_pre_cn_valid(true),
m_buy_days(0),
@ -123,6 +123,18 @@ void System::initParam() {
setParam<bool>("shared_sp", false);
}
void System::baseCheckParam(const string& name) const {
if ("max_delay_count" == name) {
HKU_ASSERT(getParam<int>("max_delay_count") >= 0);
} else if ("tp_delay_n" == name) {
HKU_ASSERT(getParam<int>("tp_delay_n") >= 0);
}
}
void System::paramChanged() {
m_calculated = false;
}
void System::reset() {
if (m_tm && !getParam<bool>("shared_tm"))
m_tm->reset();
@ -148,7 +160,7 @@ void System::reset() {
// 一个sys实例绑定stock后除非主动改变否则不应该被reset
// m_stock
m_part_changed = true;
m_calculated = false;
m_pre_ev_valid = false; // true;
m_pre_cn_valid = false; // true;
@ -189,7 +201,7 @@ void System::forceResetAll() {
m_src_kdata = Null<KData>();
m_kdata = Null<KData>();
m_part_changed = true;
m_calculated = false;
m_pre_ev_valid = false; // true;
m_pre_cn_valid = false; // true;
@ -206,10 +218,14 @@ void System::forceResetAll() {
}
void System::setTO(const KData& kdata) {
HKU_TRACE_IF_RETURN(!m_part_changed && m_kdata == kdata, void(), "No need to calcule!");
m_kdata = kdata;
m_stock = kdata.getStock();
if (m_kdata != kdata) {
m_calculated = false;
m_kdata = kdata;
}
HKU_TRACE_IF_RETURN(m_calculated, void(), "No need to calcule!");
m_stock = kdata.getStock();
KQuery query = kdata.getQuery();
if (m_stock.isNull() || query.recoverType() == KQuery::NO_RECOVER) {
m_src_kdata = m_kdata;
@ -270,7 +286,7 @@ SystemPtr System::clone() {
p->m_kdata = m_kdata;
p->m_src_kdata = m_src_kdata;
p->m_part_changed = m_part_changed;
p->m_calculated = m_calculated;
p->m_pre_ev_valid = m_pre_ev_valid;
p->m_pre_cn_valid = m_pre_cn_valid;
@ -334,7 +350,7 @@ bool System::readyForRun() {
}
void System::run(const KQuery& query, bool reset, bool resetAll) {
HKU_ERROR_IF_RETURN(m_stock.isNull(), void(), "m_stock is NULL!");
HKU_CHECK(!m_stock.isNull(), "m_stock is NULL!");
// reset必须在readyForRun之前否则m_pre_cn_valid、m_pre_ev_valid将会被赋为错误的初值
if (resetAll) {
@ -343,11 +359,10 @@ void System::run(const KQuery& query, bool reset, bool resetAll) {
this->reset();
}
HKU_IF_RETURN(!readyForRun(), void());
KData kdata = m_stock.getKData(query);
HKU_IF_RETURN(kdata.empty(), void());
HKU_DEBUG_IF_RETURN(!m_part_changed && m_kdata == kdata, void(), "Not need calculate.");
HKU_DEBUG_IF_RETURN(m_calculated && m_kdata == kdata, void(), "Not need calculate.");
HKU_IF_RETURN(!readyForRun(), void());
setTO(kdata);
size_t total = kdata.size();
@ -358,7 +373,7 @@ void System::run(const KQuery& query, bool reset, bool resetAll) {
_runMoment(ks[i], src_ks[i]);
}
}
m_part_changed = false;
m_calculated = true;
}
void System::run(const Stock& stock, const KQuery& query, bool reset, bool resetAll) {
@ -367,9 +382,6 @@ void System::run(const Stock& stock, const KQuery& query, bool reset, bool reset
}
void System::run(const KData& kdata, bool reset, bool resetAll) {
HKU_INFO_IF_RETURN(kdata.empty(), void(), "Input kdata is empty!");
HKU_DEBUG_IF_RETURN(!m_part_changed && m_kdata == kdata, void(), "Not need calculate.");
// reset必须在readyForRun之前否则m_pre_cn_valid、m_pre_ev_valid将会被赋为错误的初值
if (resetAll) {
this->forceResetAll();
@ -378,6 +390,8 @@ void System::run(const KData& kdata, bool reset, bool resetAll) {
this->reset();
}
HKU_DEBUG_IF_RETURN(m_calculated && m_kdata == kdata, void(), "Not need calculate.");
HKU_IF_RETURN(!readyForRun(), void());
setTO(kdata);
@ -389,7 +403,7 @@ void System::run(const KData& kdata, bool reset, bool resetAll) {
_runMoment(ks[i], src_ks[i]);
}
}
m_part_changed = false;
m_calculated = true;
}
void System::clearDelayRequest() {
@ -530,7 +544,12 @@ TradeRecord System::_runMoment(const KRecord& today, const KRecord& src_today) {
} else {
m_lastTakeProfit = current_take_profile;
}
if (current_price <= current_take_profile) {
int tp_delay_n = getParam<int>("tp_delay_n");
size_t pos = m_kdata.getPos(today.datetime);
size_t position_pos = m_kdata.getPos(position.takeDatetime);
// 如果当前价格小于等于止盈价,且满足止盈延迟条件则卖出
if (pos - position_pos >= tp_delay_n && current_price <= current_take_profile) {
tr = _sell(today, src_today, PART_TAKEPROFIT);
}
}

View File

@ -30,7 +30,7 @@ namespace hku {
* @ingroup System
*/
class HKU_API System {
PARAMETER_SUPPORT
PARAMETER_SUPPORT_WITH_CHECK
public:
/** 默认构造函数 */
@ -223,6 +223,11 @@ public:
return _sellForce(date, num, from, false);
}
// 由各个相关组件调用,用于组件参数变化时通知 sys以便重算
void partChangedNotify() {
m_calculated = false;
}
private:
bool _environmentIsValid(const Datetime& datetime);
bool _conditionIsValid(const Datetime& datetime);
@ -292,7 +297,7 @@ protected:
KData m_kdata;
KData m_src_kdata; // 未复权的原始 K 线数据
bool m_part_changed; // 记录部件是否发生变化,控制是否需要重新计算
bool m_calculated; // 控制是否需要重新计算
bool m_pre_ev_valid;
bool m_pre_cn_valid;
@ -334,7 +339,7 @@ private:
// m_kdata中包含了stock和query的信息不用保存m_stock
ar& BOOST_SERIALIZATION_NVP(m_kdata);
ar& BOOST_SERIALIZATION_NVP(m_part_changed);
ar& BOOST_SERIALIZATION_NVP(m_calculated);
ar& BOOST_SERIALIZATION_NVP(m_pre_ev_valid);
ar& BOOST_SERIALIZATION_NVP(m_pre_cn_valid);
@ -369,7 +374,7 @@ private:
ar& BOOST_SERIALIZATION_NVP(m_kdata);
m_stock = m_kdata.getStock();
ar& BOOST_SERIALIZATION_NVP(m_part_changed);
ar& BOOST_SERIALIZATION_NVP(m_calculated);
ar& BOOST_SERIALIZATION_NVP(m_pre_ev_valid);
ar& BOOST_SERIALIZATION_NVP(m_pre_cn_valid);
@ -451,63 +456,63 @@ inline SlippagePtr System::getSP() const {
inline void System::setTM(const TradeManagerPtr& tm) {
if (m_tm != tm) {
m_tm = tm;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setMM(const MoneyManagerPtr& mm) {
if (m_mm != mm) {
m_mm = mm;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setEV(const EnvironmentPtr& ev) {
if (m_ev != ev) {
m_ev = ev;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setCN(const ConditionPtr& cn) {
if (m_cn != cn) {
m_cn = cn;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setSG(const SignalPtr& sg) {
if (m_sg != sg) {
m_sg = sg;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setST(const StoplossPtr& st) {
if (m_st != st) {
m_st = st;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setTP(const StoplossPtr& tp) {
if (m_tp != tp) {
m_tp = tp;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setPG(const ProfitGoalPtr& pg) {
if (m_pg != pg) {
m_pg = pg;
m_part_changed = true;
m_calculated = false;
}
}
inline void System::setSP(const SlippagePtr& sp) {
if (m_sp != sp) {
m_sp = sp;
m_part_changed = true;
m_calculated = false;
}
}
@ -516,7 +521,10 @@ inline Stock System::getStock() const {
}
inline void System::setStock(const Stock& stk) {
m_stock = stk;
if (m_stock != stk) {
m_stock = stk;
m_calculated = false;
}
}
inline const TradeRecordList& System::getTradeRecordList() const {

View File

@ -352,21 +352,23 @@ public: \
/**
*
* :
* virtual void checkParam(const string& name) -- ,
* virtual void paramChanged() --
* checkParam paramChanged
*
* checkParam paramChanged 使
* setParam checkParam,
* setParam
* python python
* :
* virtual void _checkParam(const string& name) -- ,
* python paramChanged/checkParam/_checkParampython
*
*/
#define PARAMETER_SUPPORT_WITH_CHECK \
protected: \
Parameter m_params; \
virtual void checkParam(const string& name) const; \
virtual void paramChanged(); \
void paramChanged(); \
void checkParam(const string& name) const { \
baseCheckParam(name); \
_checkParam(name); \
} \
virtual void _checkParam(const string& name) const {} \
\
private: \
void baseCheckParam(const string& name) const; \
\
public: \
const Parameter& getParameter() const { \

View File

@ -26,15 +26,12 @@ TEST_CASE("test_MM_FixedCount") {
TradeManagerPtr tm = crtTM(Datetime(199001010000LL), 0.0, TC_FixedA());
/** @arg n < 1 */
MoneyManagerPtr mm = MM_FixedCount(0);
mm->setTM(tm);
int result = mm->getBuyNumber(Datetime(200101010000), stock, 10.0, 10.0, PART_SIGNAL);
CHECK_EQ(result, 0);
CHECK_THROWS_AS(MM_FixedCount(0), std::exception);
/** @arg n = 100, 一个初始资金为0的交易账户能够执行买入操作 */
tm = crtTM(Datetime(199001010000LL), 0.0, TC_FixedA());
CHECK_EQ(tm->initCash(), 0.0);
mm = MM_FixedCount(100);
auto mm = MM_FixedCount(100);
mm->setTM(tm);
mm->setParam<bool>("auto-checkin", true);
mm->getBuyNumber(Datetime(200001200000), stock, 24.11, 24.11, PART_SIGNAL);

View File

@ -23,8 +23,8 @@ TEST_CASE("test_PG_FixedHoldDays") {
StockManager& sm = StockManager::instance();
TMPtr tm = crtTM(Datetime(199001010000LL), 100000);
Datetime start_date(199911100000LL); //测试起始日期
Datetime end_date(200002250000LL); //测试结束日期
Datetime start_date(199911100000LL); // 测试起始日期
Datetime end_date(200002250000LL); // 测试结束日期
KQuery query = KQueryByDate(start_date, end_date, KQuery::DAY);
Stock stk = sm.getStock("sh600000");
@ -40,10 +40,7 @@ TEST_CASE("test_PG_FixedHoldDays") {
CHECK_EQ(pg->getParam<int>("days"), 5);
/** @arg days = 0 */
pg->setParam<int>("days", 0);
CHECK_EQ(pg->getGoal(Datetime(199911100000LL), 0.0), 0.0);
CHECK_EQ(pg->getGoal(Datetime(199911110000LL), 0.0), 0.0);
CHECK_EQ(pg->getGoal(Datetime(199911120000LL), 0.0), 0.0);
CHECK_THROWS_AS(pg->setParam<int>("days", 0), std::exception);
/** @arg days = 1 */
pg->setParam<int>("days", 1);

View File

@ -32,15 +32,20 @@ TEST_CASE("test_FixedPercent_SL") {
result = sp->getPrice(Datetime(199101030000), 66.4);
CHECK_LT(std::fabs(result - 53.12), 0.01);
/** @arg p = 0.0 */
sp = ST_FixedPercent(0.0);
/** @arg p = 0.99 */
sp = ST_FixedPercent(0.99);
result = sp->getPrice(Datetime(199101030000), 66.397);
CHECK_LT(std::fabs(result - 66.4), 0.01);
CHECK_EQ(result, doctest::Approx(roundEx(66.397 * 0.01, 2)));
/** @arg p = 1.0 */
sp = ST_FixedPercent(1.0);
result = sp->getPrice(Datetime(199101030000), 66.397);
CHECK_LT(std::fabs(result - 0), 0.01);
CHECK_EQ(result, doctest::Approx(0.0));
/** @arg 非法参数 */
CHECK_THROWS_AS(ST_FixedPercent(0.0), std::exception);
CHECK_THROWS_AS(ST_FixedPercent(1.01), std::exception);
CHECK_THROWS_AS(ST_FixedPercent(-1.0), std::exception);
}
/** @} */