Repository: ricequant/rqalpha (language: python)

Issue:
新增算法单: TVWPOrder 和 VWAPOrder



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a5429c7a0..027b6f5b2 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,21 @@
 CHANGELOG
 ==================
 
+5.0.0
+==================
+- 适配pandas2.0
+- 交易指数标的时，不检查上市日期，根据行情数据有无决定
+- 撮合时屏蔽已完成的订单
+- 修复get_prev_settlement取不到第一天的，采用prev_settlement字段
+- 新增算法单：VWAPOrder 和 TWAPOrder
+
+4.16.2
+==================
+- 修复bundle更新异常
+- 限制pandas版本为 < 2.0.0
+- sys_analyser检查基准合法性
+- sys_accounts支持分别设置股票、期货佣金倍率
+
 4.16.1
 ==================
 - 修正文档
diff --git a/docs/source/api/base_api.rst b/docs/source/api/base_api.rst
index a89889221..80f314595 100644
--- a/docs/source/api/base_api.rst
+++ b/docs/source/api/base_api.rst
@@ -141,6 +141,56 @@ after_trading - 盘后
 交易接口
 =================
 
+OrderStyle - 订单类型
+------------------------------------------------------
+
+该类型可供后续下单接口中 price_or_style 参数使用
+
+.. module:: rqalpha.model.order
+
+.. _order_style:
+
+.. autoclass:: MarketOrder
+
+    .. code-block:: python
+
+        order_shares("000001.XSHE", amount=100, price_or_style=MarketOrder())
+
+市价单
+
+.. autoclass:: LimitOrder
+
+    :param float limit_price: 价格
+
+    .. code-block:: python
+
+        order_shares("000001.XSHE", amount=100, price_or_style=LimitOrder(10))
+
+限价单
+
+.. autoclass:: TWAPOrder
+
+    :param int start_min: 分钟起始时间
+    :param int end_min: 分钟结束时间
+
+    .. code-block:: python
+
+        order_shares("000001.XSHE", amount=100, price_or_style=TWAPOrder(931, 945))
+
+算法时间加权价格订单
+
+.. autoclass:: VWAPOrder
+
+    :param int start_min: 分钟起始时间
+    :param int end_min: 分钟结束时间
+
+    .. code-block:: python
+
+        order_shares("000001.XSHE", amount=100, price_or_style=VWAPOrder(931, 945))
+
+
+算法成交量加权价格订单
+
 ..  module:: rqalpha.api
 
 submit_order - 自由参数下单「通用」
@@ -421,13 +471,14 @@ scheduler定时器
 scheduler.run_daily - 每天运行
 ------------------------------------------------------
 
-..  py:function:: scheduler.run_daily(function)
+..  py:function:: scheduler.run_daily(function, time_rule=None)
 
     每日运行一次指定的函数，只能在init内使用。
 
-    注意，schedule一定在其对应时间点的handle_bar之后执行。
+    注意，schedule一定在其对应时间点的handle_bar之前执行, 日频则忽略time_rule设置, 在当天handle_bar之前执行。
 
     :param func function: 使传入的function每日运行。注意，function函数一定要包含（并且只能包含）context, bar_dict两个输入参数
+    :param int time_rule: 通过 market_open, market_close，physical_time 来设置当天运行的时间，为None时默认为9:31分执行
 
     :example:
 
@@ -448,7 +499,7 @@ scheduler.run_daily - 每天运行
 scheduler.run_weekly - 每周运行
 ------------------------------------------------------
 
-..  py:function:: scheduler.run_weekly(function, weekday=x, tradingday=t)
+..  py:function:: scheduler.run_weekly(function, weekday=x, tradingday=t, time_rule=None)
 
     每周运行一次指定的函数，只能在init内使用。
 
@@ -464,6 +515,8 @@ scheduler.run_weekly - 每周运行
 
     :param int tradingday: 范围为[-5,1],[1,5] 例如，1代表每周第一个交易日，-1代表每周倒数第一个交易日，用户可以不填写。
 
+    :param int time_rule: 通过 market_open, market_close，physical_time 来设置当天运行的时间，为None时默认为9:31分执行
+
     :example:
 
     以下的代码片段非常简单，在每周二固定运行打印一下现在的portfolio剩余的资金:
@@ -485,7 +538,7 @@ scheduler.run_weekly - 每周运行
 scheduler.run_monthly - 每月运行
 ------------------------------------------------------
 
-..  py:function:: scheduler.run_monthly(function, tradingday=t)
+..  py:function:: scheduler.run_monthly(function, tradingday=t, time_rule=None)
 
     每月运行一次指定的函数，只能在init内使用。
 
@@ -498,6 +551,8 @@ scheduler.run_monthly - 每月运行
 
     :param int tradingday: 范围为[-23,1], [1,23] ，例如，1代表每月第一个交易日，-1代表每月倒数第一个交易日，用户必须指定。
 
+    :param int time_rule: 通过 market_open, market_close，physical_time 来设置当天运行的时间，为None时默认为9:31分执行
+
     :example:
 
     以下的代码片段非常简单的展示了每个月第一个交易日的时候我们进行一次财务数据查询，这对根据财务数据来调节股票组合的策略会非常有用:
@@ -646,6 +701,8 @@ Order - 订单
 ------------------------------------------------------
 ..  module:: rqalpha.model.order
 
+.. _order:
+
 ..  autoclass:: Order
     :members:
     :show-inheritance:
@@ -873,6 +930,10 @@ ORDER_TYPE - 订单类型
 
         限价单
 
+    .. py:attribute:: ALGO
+
+        算法单
+
 
 ORDER_STATUS - 订单状态
 ------------------------------------------------------
diff --git a/rqalpha/apis/api_abstract.py b/rqalpha/apis/api_abstract.py
index 154507ae9..0d11cf90d 100644
--- a/rqalpha/apis/api_abstract.py
+++ b/rqalpha/apis/api_abstract.py
@@ -15,17 +15,32 @@
 #         在此前提下，对本软件的使用同样需要遵守 Apache 2.0 许可，Apache 2.0 许可与本许可冲突之处，以本许可为准。
 #         详细的授权流程，请联系 public@ricequant.com 获取。
 
-from typing import Union, Optional, List
+from typing import Union, Optional, List, Tuple
 
 from rqalpha.api import export_as_api
 from rqalpha.core.execution_context import ExecutionContext
 from rqalpha.const import EXECUTION_PHASE
 from rqalpha.model.instrument import Instrument
-from rqalpha.model.order import MarketOrder, LimitOrder, OrderStyle, Order
+from rqalpha.model.order import MarketOrder, LimitOrder, OrderStyle, Order, ALL_ORDER_STYPES
 from rqalpha.utils.arg_checker import apply_rules, verify_that
 from rqalpha.utils.functools import instype_singledispatch
 
 
+common_rules = (
+    verify_that('price', pre_check=True).deprecated("please use price_or_style instead.").is_greater_than(0),
+    verify_that('style', pre_check=True).deprecated("please use price_or_style instead.").is_instance_of(
+        (*ALL_ORDER_STYPES, type(None))
+    ),
+    verify_that("price_or_style", pre_check=True).is_instance_of((float, type(None), tuple, *ALL_ORDER_STYPES)),
+)
+
+
+PRICE_OR_STYLE_TYPE = Union[float, OrderStyle, None]
+TUPLE_PRICE_OR_STYLE_TYPE = Union[
+    float, OrderStyle, None, Tuple, Tuple[PRICE_OR_STYLE_TYPE], Tuple[PRICE_OR_STYLE_TYPE, PRICE_OR_STYLE_TYPE]
+]
+
+
 @export_as_api
 @ExecutionContext.enforce_phase(
     EXECUTION_PHASE.OPEN_AUCTION,
@@ -36,11 +51,11 @@
 )
 @apply_rules(
     verify_that('amount').is_number(),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def order_shares(id_or_ins, amount, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> Optional[Order]
+def order_shares(id_or_ins, amount, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> Optional[Order]
     """
     指定股数的买/卖单，最常见的落单方式之一。如有需要落单类型当做一个参量传入，如果忽略掉落单类型，那么默认是市价单（market order）。
 
@@ -48,6 +63,8 @@ def order_shares(id_or_ins, amount, price=None, style=None):
     :param amount: 下单量, 正数代表买入，负数代表卖出。将会根据一手xx股来向下调整到一手的倍数，比如中国A股就是调整成100股的倍数。
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -57,8 +74,12 @@ def order_shares(id_or_ins, amount, price=None, style=None):
         order_shares('000001.XSHE', 2000)
         #卖出2000股的平安银行股票，并以市价单发送：
         order_shares('000001.XSHE', -2000)
+        #购买1000股的平安银行股票，并以限价单发送，价格为￥11：
+        order_shares('000001.XSHG', 1000, price_or_style=11)
         #购买1000股的平安银行股票，并以限价单发送，价格为￥10：
-        order_shares('000001.XSHG', 1000, style=LimitOrder(10))
+        order_shares('000001.XSHG', 1000, price_or_style=LimitOrder(10))
+        #购买1000股的平安银行股票，并以 9:31 到 9:45 的VWAP价格发送：
+        order_shares('000001.XSHG', 1000, price_or_style=VWAPOrder(931, 945))
     """
     raise NotImplementedError
 
@@ -73,11 +94,11 @@ def order_shares(id_or_ins, amount, price=None, style=None):
 )
 @apply_rules(
     verify_that('cash_amount').is_number(),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def order_value(id_or_ins, cash_amount, price=None, style=None):
-    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle]) -> Optional[Order]
+def order_value(id_or_ins, cash_amount, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> Optional[Order]
     """
     使用想要花费的金钱买入/卖出股票，而不是买入/卖出想要的股数，正数代表买入，负数代表卖出。股票的股数总是会被调整成对应的100的倍数（在A中国A股市场1手是100股）。
     如果资金不足，该API将会使用最大可用资金发单。
@@ -90,6 +111,8 @@ def order_value(id_or_ins, cash_amount, price=None, style=None):
     :param cash_amount: 需要花费现金购买/卖出证券的数目。正数代表买入，负数代表卖出。
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -97,8 +120,8 @@ def order_value(id_or_ins, cash_amount, price=None, style=None):
 
         #花费最多￥10000买入平安银行股票，并以市价单发送。具体下单的数量与您策略税费相关的配置有关。
         order_value('000001.XSHE', 10000)
-        #卖出价值￥10000的现在持有的平安银行：
-        order_value('000001.XSHE', -10000)
+        #卖出价值￥10000的现在持有的平安银行, 以10￥价格发出限价单：
+        order_value('000001.XSHE', -10000, price_or_style=10)
     """
     raise NotImplementedError
 
@@ -113,11 +136,11 @@ def order_value(id_or_ins, cash_amount, price=None, style=None):
 )
 @apply_rules(
     verify_that('percent', pre_check=True).is_number().is_greater_or_equal_than(-1).is_less_or_equal_than(1),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def order_percent(id_or_ins, percent, price=None, style=None):
-    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle]) -> Optional[Order]
+def order_percent(id_or_ins, percent, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> Optional[Order]
     """
     发送一个花费价值等于目前投资组合（市场价值和目前现金的总和）一定百分比现金的买/卖单，正数代表买，负数代表卖。股票的股数总是会被调整成对应的一手的股票数的倍数（1手是100股）。百分比是一个小数，并且小于或等于1（<=100%），0.5表示的是50%.需要注意，如果资金不足，该API将会使用最大可用资金发单。
 
@@ -130,6 +153,8 @@ def order_percent(id_or_ins, percent, price=None, style=None):
     :param percent: 占有现有的投资组合价值的百分比。正数表示买入，负数表示卖出。
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -137,6 +162,8 @@ def order_percent(id_or_ins, percent, price=None, style=None):
 
         #花费等于现有投资组合50%价值的现金买入平安银行股票：
         order_percent('000001.XSHG', 0.5)
+        #花费等于现有投资组合50%价值的现金买入平安银行股票, 以10￥限价单：
+        order_percent('000001.XSHG', 0.5, price_or_style=10)
     """
     raise NotImplementedError
 
@@ -151,11 +178,11 @@ def order_percent(id_or_ins, percent, price=None, style=None):
 )
 @apply_rules(
     verify_that('cash_amount').is_number(),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def order_target_value(id_or_ins, cash_amount, price=None, style=None):
-    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle]) -> Optional[Order]
+def order_target_value(id_or_ins, cash_amount, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle], TUPLE_PRICE_OR_STYLE_TYPE) -> Optional[Order]
     """
     买入/卖出并且自动调整该证券的仓位到一个目标价值。
     加仓时，cash_amount 代表现有持仓的价值加上即将花费（包含税费）的现金的总价值。
@@ -167,6 +194,8 @@ def order_target_value(id_or_ins, cash_amount, price=None, style=None):
     :param cash_amount: 最终的该证券的仓位目标价值。
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -174,6 +203,9 @@ def order_target_value(id_or_ins, cash_amount, price=None, style=None):
 
         #如果现在的投资组合中持有价值￥3000的平安银行股票的仓位，以下代码范例会发送花费 ￥7000 现金的平安银行买单到市场。（向下调整到最接近每手股数即100的倍数的股数）：
         order_target_value('000001.XSHE', 10000)
+        #如果现在的投资组合中持有价值￥3000的平安银行股票的仓位，以下代码范例会发送10￥限价单共花费 ￥7000 现金的平安银行买单到市场
+        #或者如果现在的投资组合中持有价值￥13000的平安银行股票的仓位，以下代码范例会发送11￥限价单共花费 ￥3000 现金的平安银行卖单到市场
+        order_target_value('000001.XSHE', 10000, price_or_style=(10, 11)
     """
     raise NotImplementedError
 
@@ -188,11 +220,11 @@ def order_target_value(id_or_ins, cash_amount, price=None, style=None):
 )
 @apply_rules(
     verify_that('percent', pre_check=True).is_number().is_greater_or_equal_than(0).is_less_or_equal_than(1),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def order_target_percent(id_or_ins, percent, price=None, style=None):
-    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle]) -> Optional[Order]
+def order_target_percent(id_or_ins, percent, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle], TUPLE_PRICE_OR_STYLE_TYPE) -> Optional[Order]
     """
     买入/卖出证券以自动调整该证券的仓位到占有一个目标价值。
 
@@ -213,6 +245,8 @@ def order_target_percent(id_or_ins, percent, price=None, style=None):
     :param percent: 仓位最终所占投资组合总价值的目标百分比。
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -220,6 +254,9 @@ def order_target_percent(id_or_ins, percent, price=None, style=None):
 
         #如果投资组合中已经有了平安银行股票的仓位，并且占据目前投资组合的10%的价值，那么以下代码会消耗相当于当前投资组合价值5%的现金买入平安银行股票：
         order_target_percent('000001.XSHE', 0.15)
+        #如果投资组合中已经有了平安银行股票的仓位，并且占据目前投资组合的10%的价值，那么以下代码会消耗相当于当前投资组合价值5%的现金以10￥限价单买入平安银行股票：
+        #或者如果投资组合中已经有了平安银行股票的仓位，并且占据目前投资组合的20%的价值，那么以下代码会消耗相当于当前投资组合价值5%的现金以11￥限价单卖出平安银行股票：
+        order_target_percent('000001.XSHE', 0.15, price_or_style=(10, 11))
     """
     raise NotImplementedError
 
@@ -234,11 +271,11 @@ def order_target_percent(id_or_ins, percent, price=None, style=None):
 )
 @apply_rules(
     verify_that('amount', pre_check=True).is_number().is_greater_or_equal_than(0),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def buy_open(id_or_ins, amount, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> Union[Order, List[Order], None]
+def buy_open(id_or_ins, amount, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> Union[Order, List[Order], None]
     """
     买入开仓。
 
@@ -246,13 +283,15 @@ def buy_open(id_or_ins, amount, price=None, style=None):
     :param amount: 下单手数
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
     .. code-block:: python
 
         #以价格为3500的限价单开仓买入2张上期所AG1607合约：
-        buy_open('AG1607', amount=2, price=3500))
+        buy_open('AG1607', amount=2, price_or_style=3500))
     """
     raise NotImplementedError
 
@@ -267,11 +306,11 @@ def buy_open(id_or_ins, amount, price=None, style=None):
 )
 @apply_rules(
     verify_that('amount', pre_check=True).is_number().is_greater_or_equal_than(0),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def buy_close(id_or_ins, amount, price=None, style=None, close_today=False):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], Optional[bool]) -> Union[Order, List[Order], None]
+def buy_close(id_or_ins, amount, price=None, style=None, price_or_style=None, close_today=False):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE, Optional[bool]) -> Union[Order, List[Order], None]
     """
     平卖仓
 
@@ -280,6 +319,8 @@ def buy_close(id_or_ins, amount, price=None, style=None, close_today=False):
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
     :param close_today: 是否指定发平今仓单，默认为False，发送平仓单
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -301,11 +342,11 @@ def buy_close(id_or_ins, amount, price=None, style=None, close_today=False):
 )
 @apply_rules(
     verify_that('amount', pre_check=True).is_number().is_greater_or_equal_than(0),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def sell_open(id_or_ins, amount, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> Union[Order, List[Order], None]
+def sell_open(id_or_ins, amount, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> Union[Order, List[Order], None]
     """
     卖出开仓
 
@@ -313,6 +354,16 @@ def sell_open(id_or_ins, amount, price=None, style=None):
     :param amount: 下单手数
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
+
+    :example:
+
+    .. code-block:: python
+
+        # 以3100发出限价单将现有IF1603卖出开仓2张：
+        sell_open('IF1603', 2, price_or_style=3100)
+
     """
     raise NotImplementedError
 
@@ -327,11 +378,11 @@ def sell_open(id_or_ins, amount, price=None, style=None):
 )
 @apply_rules(
     verify_that('amount', pre_check=True).is_number().is_greater_or_equal_than(0),
-    verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None)))
+    *common_rules
 )
 @instype_singledispatch
-def sell_close(id_or_ins, amount, price=None, style=None, close_today=False):
-    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle], Optional[bool]) -> Union[Order, List[Order], None]
+def sell_close(id_or_ins, amount, price=None, style=None, price_or_style=None, close_today=False):
+    # type: (Union[str, Instrument], float, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE, Optional[bool]) -> Union[Order, List[Order], None]
     """
     平买仓
 
@@ -340,15 +391,26 @@ def sell_close(id_or_ins, amount, price=None, style=None, close_today=False):
     :param price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
     :param close_today: 是否指定发平今仓单，默认为False，发送平仓单
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
+
+    :example:
+
+    .. code-block:: python
+
+        # 以市价单单将现有IF1603买入平仓2张：
+        sell_close('IF1603', 2, price_or_style=MarketOrder())
+
+
     """
     raise NotImplementedError
 
 
 @export_as_api
-@apply_rules(verify_that("quantity").is_number())
+@apply_rules(verify_that("quantity").is_number(), *common_rules)
 @instype_singledispatch
-def order(order_book_id, quantity, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> List[Order]
+def order(order_book_id, quantity, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> List[Order]
     """
       全品种通用智能调仓函数
 
@@ -366,6 +428,8 @@ def order(order_book_id, quantity, price=None, style=None):
       :param quantity: 调仓量
       :param price: 下单价格
       :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+      :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
       :example:
 
@@ -384,10 +448,10 @@ def order(order_book_id, quantity, price=None, style=None):
 
 
 @export_as_api
-@apply_rules(verify_that("quantity").is_number())
+@apply_rules(verify_that("quantity").is_number(), *common_rules)
 @instype_singledispatch
-def order_to(order_book_id, quantity, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> List[Order]
+def order_to(order_book_id, quantity, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> List[Order]
     """
     全品种通用智能调仓函数
 
@@ -405,6 +469,9 @@ def order_to(order_book_id, quantity, price=None, style=None):
     :param int quantity: 调仓量
     :param float price: 下单价格
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
+
     :example:
 
     ..  code-block:: python3
diff --git a/rqalpha/apis/api_base.py b/rqalpha/apis/api_base.py
index 722a0e638..7b2aff5a4 100644
--- a/rqalpha/apis/api_base.py
+++ b/rqalpha/apis/api_base.py
@@ -39,7 +39,7 @@
     EXECUTION_PHASE, ORDER_STATUS, SIDE, POSITION_EFFECT, ORDER_TYPE, MATCHING_TYPE, RUN_TYPE, POSITION_DIRECTION,
     DEFAULT_ACCOUNT_TYPE
 )
-from rqalpha.model.order import Order, MarketOrder, LimitOrder, OrderStyle
+from rqalpha.model.order import Order, MarketOrder, LimitOrder, OrderStyle, VWAPOrder, TWAPOrder
 from rqalpha.core.events import EVENT, Event
 from rqalpha.core.strategy_context import StrategyContext
 from rqalpha.portfolio.position import Position
@@ -48,6 +48,8 @@
 export_as_api(user_print, name='print')
 export_as_api(LimitOrder, name='LimitOrder')
 export_as_api(MarketOrder, name='MarketOrder')
+export_as_api(VWAPOrder, name='VWAPOrder')
+export_as_api(TWAPOrder, name='TWAPOrder')
 export_as_api(ORDER_STATUS, name='ORDER_STATUS')
 export_as_api(SIDE, name='SIDE')
 export_as_api(POSITION_EFFECT, name='POSITION_EFFECT')
@@ -71,26 +73,40 @@ def assure_order_book_id(id_or_ins):
     return assure_instrument(id_or_ins).order_book_id
 
 
-def cal_style(price, style):
-    if price is None and style is None:
+def cal_style(price, style, price_or_style=None):
+    if price_or_style is None:
+        if price:
+            price_or_style = price
+        if style:
+            price_or_style = style
+
+    if price_or_style is None:
         return MarketOrder()
 
-    if style is not None:
-        if not isinstance(style, OrderStyle):
-            raise RuntimeError
-        return style
+    if not isinstance(price_or_style, (int, float, OrderStyle)):
+        raise RQInvalidArgument(f"price or style or price_or_style type no support. {price_or_style}")
+
+    if isinstance(price_or_style, OrderStyle):
+        return price_or_style
 
-    if isinstance(price, OrderStyle):
-        # 为了 order_xxx('RB1710', 10, MarketOrder()) 这种写法
-        if isinstance(price, LimitOrder):
-            if np.isnan(price.get_limit_price()):
-                raise RQInvalidArgument(_(u"Limit order price should not be nan."))
-        return price
+    return LimitOrder(price_or_style)
 
-    if np.isnan(price):
-        raise RQInvalidArgument(_(u"Limit order price should not be nan."))
 
-    return LimitOrder(price)
+def calc_open_close_style(price, style, price_or_style):
+    if isinstance(price_or_style, tuple):
+        _length = len(price_or_style)
+        if _length == 0:
+            o, c = None, None
+        elif _length == 1:
+            o, c = price_or_style[0], price_or_style[0]
+        else:
+            o, c = price_or_style[0], price_or_style[1]
+        open_style = cal_style(price, style, o)
+        close_style = cal_style(price, style, c)
+    else:
+        open_style = cal_style(price, style, price_or_style)
+        close_style = open_style
+    return open_style, close_style
 
 
 @export_as_api
diff --git a/rqalpha/const.py b/rqalpha/const.py
index be92a3bc8..2eba03a2e 100644
--- a/rqalpha/const.py
+++ b/rqalpha/const.py
@@ -94,6 +94,12 @@ class MATCHING_TYPE(CustomEnum):
 class ORDER_TYPE(CustomEnum):
     MARKET = "MARKET"
     LIMIT = "LIMIT"
+    ALGO = "ALGO"
+
+
+class ALGO(CustomEnum):
+    TWAP = "TWAP"
+    VWAP = "VWAP"
 
 
 # noinspection PyPep8Naming
diff --git a/rqalpha/data/base_data_source/data_source.py b/rqalpha/data/base_data_source/data_source.py
index ba0e9fc98..fe42cc091 100644
--- a/rqalpha/data/base_data_source/data_source.py
+++ b/rqalpha/data/base_data_source/data_source.py
@@ -367,3 +367,6 @@ def get_merge_ticks(self, order_book_id_list, trading_date, last_dt=None):
 
     def history_ticks(self, instrument, count, dt):
         raise NotImplementedError
+
+    def get_algo_bar(self, id_or_ins, start_min, end_min, dt):
+        raise NotImplementedError("open source rqalpha not support algo order")
diff --git a/rqalpha/data/bundle.py b/rqalpha/data/bundle.py
index b15284e28..d01f40b2f 100644
--- a/rqalpha/data/bundle.py
+++ b/rqalpha/data/bundle.py
@@ -75,12 +75,13 @@ def gen_suspended_days(d):
 def gen_dividends(d):
     stocks = rqdatac.all_instruments().order_book_id.tolist()
     dividend = rqdatac.get_dividend(stocks)
+    need_cols = ["dividend_cash_before_tax", "book_closure_date", "ex_dividend_date", "payable_date", "round_lot"]
+    dividend = dividend[need_cols]
     dividend.reset_index(inplace=True)
     dividend.rename(columns={'declaration_announcement_date': 'announcement_date'}, inplace=True)
     for f in ('book_closure_date', 'ex_dividend_date', 'payable_date', 'announcement_date'):
         dividend[f] = [convert_date_to_date_int(d) for d in dividend[f]]
     dividend.set_index(['order_book_id', 'book_closure_date'], inplace=True)
-    dividend.drop(columns=["advance_date", "quarter"], inplace=True)
     with h5py.File(os.path.join(d, 'dividends.h5'), 'w') as h5:
         for order_book_id in dividend.index.levels[0]:
             h5[order_book_id] = dividend.loc[order_book_id].to_records()
diff --git a/rqalpha/data/data_proxy.py b/rqalpha/data/data_proxy.py
index f7e416e29..2eab1f09d 100644
--- a/rqalpha/data/data_proxy.py
+++ b/rqalpha/data/data_proxy.py
@@ -16,7 +16,7 @@
 #         详细的授权流程，请联系 public@ricequant.com 获取。
 
 from datetime import datetime, date
-from typing import Union, List, Sequence, Optional
+from typing import Union, List, Sequence, Optional, Tuple
 
 import six
 import numpy as np
@@ -28,6 +28,7 @@
 from rqalpha.model.bar import BarObject, NANDict, PartialBarObject
 from rqalpha.model.tick import TickObject
 from rqalpha.model.instrument import Instrument
+from rqalpha.model.order import TWAPOrder, VWAPOrder, ALGO_ORDER_STYLES
 from rqalpha.utils.functools import lru_cache
 from rqalpha.utils.datetime_func import convert_int_to_datetime, convert_date_to_int
 from rqalpha.utils.typing import DateLike, StrOrIter
@@ -130,9 +131,9 @@ def get_prev_close(self, order_book_id, dt):
 
     @lru_cache(10240)
     def _get_prev_settlement(self, instrument, dt):
-        prev_trading_date = self.get_previous_trading_date(dt)
-        bar = self._data_source.history_bars(instrument, 1, '1d', 'settlement', prev_trading_date,
-                                             skip_suspended=False, adjust_orig=dt)
+        bar = self._data_source.history_bars(
+            instrument, 1, '1d', fields='prev_settlement', dt=dt, skip_suspended=False, adjust_orig=dt
+        )
         if bar is None or len(bar) == 0:
             return np.nan
         return bar[0]
@@ -303,3 +304,16 @@ def get_trading_period(self, sym_or_ids, default_trading_period=None):
     def is_night_trading(self, sym_or_ids):
         # type: (StrOrIter) -> bool
         return any((instrument.trade_at_night for instrument in self.instruments(sym_or_ids)))
+
+    def get_algo_bar(self, id_or_ins, order_style, dt):
+        # type: (Union[str, Instrument], Union[*ALGO_ORDER_STYLES], datetime) -> Tuple[float, int]
+        if not isinstance(order_style, ALGO_ORDER_STYLES):
+            raise RuntimeError("get_algo_bar only support VWAPOrder and TWAPOrder")
+        if not isinstance(id_or_ins, Instrument):
+            id_or_ins = self.instrument(id_or_ins)
+        if id_or_ins is None:
+            return np.nan, 0
+        bar = self._data_source.get_algo_bar(id_or_ins, order_style.start_min, order_style.end_min, dt)
+        return (bar[order_style.TYPE], bar["volume"]) if bar else (np.nan, 0)
+
+
diff --git a/rqalpha/data/trading_dates_mixin.py b/rqalpha/data/trading_dates_mixin.py
index 08e655580..84ea7315f 100644
--- a/rqalpha/data/trading_dates_mixin.py
+++ b/rqalpha/data/trading_dates_mixin.py
@@ -75,7 +75,7 @@ def get_next_trading_date(self, date, n=1, trading_calendar_type=None):
     def is_trading_date(self, date, trading_calendar_type=None):
         trading_dates = self.get_trading_calendar(trading_calendar_type)
         pos = trading_dates.searchsorted(_to_timestamp(date))
-        return pos < len(trading_dates) and trading_dates[pos] == date
+        return pos < len(trading_dates) and trading_dates[pos].date() == date
 
     def get_trading_dt(self, calendar_dt):
         trading_date = self.get_future_trading_date(calendar_dt)
diff --git a/rqalpha/environment.py b/rqalpha/environment.py
index 08c014bcf..02673a480 100644
--- a/rqalpha/environment.py
+++ b/rqalpha/environment.py
@@ -185,4 +185,5 @@ def can_submit_order(self, order):
         for v in self._get_frontend_validators(instrument_type):
             if not v.can_submit_order(order, account):
                 return False
-        return True
\ No newline at end of file
+        return True
+
diff --git a/rqalpha/interface.py b/rqalpha/interface.py
index 3519069f5..91261a495 100644
--- a/rqalpha/interface.py
+++ b/rqalpha/interface.py
@@ -445,6 +445,11 @@ def is_st_stock(self, order_book_id, dates):
         # type: (str, Sequence[DateLike]) -> Sequence[bool]
         raise NotImplementedError
 
+    def get_algo_bar(self, id_or_ins, start_min, end_min, dt):
+        # type: (Union[str, Instrument], int, int, datetime) -> Optional[numpy.void]
+        # 格式: (date, VWAP, TWAP, volume) -> 案例 (20200102, 16.79877183, 16.83271429, 144356044)
+        raise NotImplementedError
+
 
 class AbstractBroker(with_metaclass(abc.ABCMeta)):
     """
diff --git a/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_future.py b/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_future.py
index d5afb76c7..8b93fc857 100644
--- a/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_future.py
+++ b/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_future.py
@@ -18,13 +18,15 @@
 from __future__ import division
 from typing import Union, Optional, List
 
+import numpy as np
+
 from rqalpha.api import export_as_api
 from rqalpha.apis.api_base import assure_instrument
 from rqalpha.apis.api_abstract import order, order_to, buy_open, buy_close, sell_open, sell_close
 from rqalpha.apis.api_base import cal_style
 from rqalpha.apis.api_rqdatac import futures
 from rqalpha.environment import Environment
-from rqalpha.model.order import Order, LimitOrder, OrderStyle
+from rqalpha.model.order import Order, LimitOrder, OrderStyle, ALGO_ORDER_STYLES
 from rqalpha.const import SIDE, POSITION_EFFECT, ORDER_TYPE, RUN_TYPE, INSTRUMENT_TYPE, POSITION_DIRECTION
 from rqalpha.model.instrument import Instrument
 from rqalpha.portfolio.position import Position
@@ -35,8 +37,7 @@
 from rqalpha.utils.arg_checker import apply_rules, verify_that
 
 
-__all__ = [
-]
+__all__ = []
 
 
 def _submit_order(id_or_ins, amount, side, position_effect, style):
@@ -50,9 +51,8 @@ def _submit_order(id_or_ins, amount, side, position_effect, style):
             u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}"
         ).format(order_book_id=order_book_id))
         return None
-    if isinstance(style, LimitOrder) and style.get_limit_price() <= 0:
-        raise RQInvalidArgument(_(u"Limit order price should be positive"))
-
+    if isinstance(style, LimitOrder) and np.isnan(style.get_limit_price()):
+        raise RQInvalidArgument(_(u"Limit order price should not be nan."))
 
     if env.config.base.run_type != RUN_TYPE.BACKTEST and instrument.type == INSTRUMENT_TYPE.FUTURE:
         if "88" in order_book_id:
@@ -121,8 +121,6 @@ def _submit_order(id_or_ins, amount, side, position_effect, style):
         )
 
     for o in orders:
-        if o.type == ORDER_TYPE.MARKET:
-            o.set_frozen_price(price)
         if env.can_submit_order(o):
             env.broker.submit_order(o)
         else:
@@ -176,37 +174,37 @@ def _order(order_book_id, quantity, style, target):
 
 
 @order.register(INSTRUMENT_TYPE.FUTURE)
-def future_order(order_book_id, quantity, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> List[Order]
-    return _order(order_book_id, quantity, cal_style(price, style), False)
+def future_order(order_book_id, quantity, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], Optional[Union[float, OrderStyle]]) -> List[Order]
+    return _order(order_book_id, quantity, cal_style(price, style, price_or_style), False)
 
 
 @order_to.register(INSTRUMENT_TYPE.FUTURE)
-def future_order_to(order_book_id, quantity, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> List[Order]
-    return _order(order_book_id, quantity, cal_style(price, style), True)
+def future_order_to(order_book_id, quantity, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], Optional[Union[float, OrderStyle]]) -> List[Order]
+    return _order(order_book_id, quantity, cal_style(price, style, price_or_style), True)
 
 
 @buy_open.register(INSTRUMENT_TYPE.FUTURE)
-def future_buy_open(id_or_ins, amount, price=None, style=None):
-    return _submit_order(id_or_ins, amount, SIDE.BUY, POSITION_EFFECT.OPEN, cal_style(price, style))
+def future_buy_open(id_or_ins, amount, price=None, style=None, price_or_style=None):
+    return _submit_order(id_or_ins, amount, SIDE.BUY, POSITION_EFFECT.OPEN, cal_style(price, style, price_or_style))
 
 
 @buy_close.register(INSTRUMENT_TYPE.FUTURE)
-def future_buy_close(id_or_ins, amount, price=None, style=None, close_today=False):
+def future_buy_close(id_or_ins, amount, price=None, style=None, close_today=False, price_or_style=None):
     position_effect = POSITION_EFFECT.CLOSE_TODAY if close_today else POSITION_EFFECT.CLOSE
-    return _submit_order(id_or_ins, amount, SIDE.BUY, position_effect, cal_style(price, style))
+    return _submit_order(id_or_ins, amount, SIDE.BUY, position_effect, cal_style(price, style, price_or_style))
 
 
 @sell_open.register(INSTRUMENT_TYPE.FUTURE)
-def future_sell_open(id_or_ins, amount, price=None, style=None):
-    return _submit_order(id_or_ins, amount, SIDE.SELL, POSITION_EFFECT.OPEN, cal_style(price, style))
+def future_sell_open(id_or_ins, amount, price=None, style=None, price_or_style=None):
+    return _submit_order(id_or_ins, amount, SIDE.SELL, POSITION_EFFECT.OPEN, cal_style(price, style, price_or_style))
 
 
 @sell_close.register(INSTRUMENT_TYPE.FUTURE)
-def future_sell_close(id_or_ins, amount, price=None, style=None, close_today=False):
+def future_sell_close(id_or_ins, amount, price=None, style=None, close_today=False, price_or_style=None):
     position_effect = POSITION_EFFECT.CLOSE_TODAY if close_today else POSITION_EFFECT.CLOSE
-    return _submit_order(id_or_ins, amount, SIDE.SELL, position_effect, cal_style(price, style))
+    return _submit_order(id_or_ins, amount, SIDE.SELL, position_effect, cal_style(price, style, price_or_style))
 
 
 @export_as_api
diff --git a/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_stock.py b/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_stock.py
index d064697d5..494949bb2 100644
--- a/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_stock.py
+++ b/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_stock.py
@@ -26,9 +26,10 @@
 from rqalpha.apis.api_abstract import (order, order_percent, order_shares,
                                        order_target_percent,
                                        order_target_value, order_to,
-                                       order_value)
+                                       order_value,
+                                       common_rules, TUPLE_PRICE_OR_STYLE_TYPE, PRICE_OR_STYLE_TYPE)
 from rqalpha.apis.api_base import (assure_instrument, assure_order_book_id,
-                                   cal_style)
+                                   cal_style, calc_open_close_style)
 from rqalpha.const import (DEFAULT_ACCOUNT_TYPE, EXECUTION_PHASE,
                            INSTRUMENT_TYPE, ORDER_TYPE, POSITION_DIRECTION,
                            POSITION_EFFECT, SIDE)
@@ -40,7 +41,7 @@
 from rqalpha.model.instrument import IndustryCodeItem, Instrument
 from rqalpha.model.instrument import SectorCode as sector_code
 from rqalpha.model.instrument import SectorCodeItem
-from rqalpha.model.order import LimitOrder, MarketOrder, Order, OrderStyle
+from rqalpha.model.order import LimitOrder, MarketOrder, Order, OrderStyle, ALGO_ORDER_STYLES
 from rqalpha.utils import INST_TYPE_IN_STOCK_ACCOUNT, is_valid_price
 from rqalpha.utils.arg_checker import apply_rules, verify_that
 from rqalpha.utils.datetime_func import to_date
@@ -80,11 +81,23 @@ def _round_order_quantity(ins, quantity) -> int:
         except ValueError:
             raise
 
+
+def _get_order_style_price(order_book_id, style):
+    if isinstance(style, LimitOrder):
+        return style.get_limit_price()
+    env = Environment.get_instance()
+    if isinstance(style, MarketOrder):
+        return env.data_proxy.get_last_price(order_book_id)
+    if isinstance(style, ALGO_ORDER_STYLES):
+        price, _ = env.data_proxy.get_algo_bar(order_book_id, style, env.calendar_dt)
+        return price
+    raise RuntimeError(f"no support {style} order style")
+
+
 def _submit_order(ins, amount, side, position_effect, style, current_quantity, auto_switch_order_value):
     env = Environment.get_instance()
-    if isinstance(style, LimitOrder):
-        if not is_valid_price(style.get_limit_price()):
-            raise RQInvalidArgument(_(u"Limit order price should be positive"))
+    if isinstance(style, LimitOrder) and np.isnan(style.get_limit_price()):
+        raise RQInvalidArgument(_(u"Limit order price should not be nan."))
     price = env.data_proxy.get_last_price(ins.order_book_id)
     if not is_valid_price(price):
         user_system_log.warn(
@@ -100,8 +113,6 @@ def _submit_order(ins, amount, side, position_effect, style, current_quantity, a
         ).format(order_book_id=ins.order_book_id))
         return
     order = Order.__from_create__(ins.order_book_id, abs(amount), side, style, position_effect)
-    if order.type == ORDER_TYPE.MARKET:
-        order.set_frozen_price(price)
     if side == SIDE.BUY and auto_switch_order_value:
         account, position, ins = _get_account_position_ins(ins)
         if not is_cash_enough(env, order, account.cash):
@@ -155,59 +166,68 @@ def _order_value(account, position, ins, cash_amount, style):
 
 
 @order_shares.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order_shares(id_or_ins, amount, price=None, style=None):
+def stock_order_shares(id_or_ins, amount, price=None, style=None, price_or_style=None):
     auto_switch_order_value = Environment.get_instance().config.mod.sys_accounts.auto_switch_order_value
     account, position, ins = _get_account_position_ins(id_or_ins)
-    return _order_shares(assure_instrument(id_or_ins), amount, cal_style(price, style), position.quantity,
-                         auto_switch_order_value)
+    return _order_shares(
+        assure_instrument(id_or_ins), amount, cal_style(price, style, price_or_style), position.quantity,
+        auto_switch_order_value
+    )
 
 
 @order_value.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order_value(id_or_ins, cash_amount, price=None, style=None):
+def stock_order_value(id_or_ins, cash_amount, price=None, style=None, price_or_style=None):
     account, position, ins = _get_account_position_ins(id_or_ins)
-    return _order_value(account, position, ins, cash_amount, cal_style(price, style))
+    return _order_value(account, position, ins, cash_amount, cal_style(price, style, price_or_style))
 
 
 @order_percent.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order_percent(id_or_ins, percent, price=None, style=None):
+def stock_order_percent(id_or_ins, percent, price=None, style=None, price_or_style=None):
     account, position, ins = _get_account_position_ins(id_or_ins)
-    return _order_value(account, position, ins, account.total_value * percent, cal_style(price, style))
+    return _order_value(account, position, ins, account.total_value * percent, cal_style(price, style, price_or_style))
 
 
 @order_target_value.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order_target_value(id_or_ins, cash_amount, price=None, style=None):
+def stock_order_target_value(id_or_ins, cash_amount, price=None, style=None, price_or_style=None):
     account, position, ins = _get_account_position_ins(id_or_ins)
+    open_style, close_style = calc_open_close_style(price, style, price_or_style)
     if cash_amount == 0:
-        return _submit_order(ins, position.closable, SIDE.SELL, POSITION_EFFECT.CLOSE, cal_style(price, style),
-                             position.quantity, False)
-    return _order_value(account, position, ins, cash_amount - position.market_value, cal_style(price, style))
+        return _submit_order(
+            ins, position.closable, SIDE.SELL, POSITION_EFFECT.CLOSE, close_style, position.quantity, False
+        )
+    _delta = cash_amount - position.market_value
+    _style = open_style if _delta > 0 else close_style
+    return _order_value(account, position, ins, _delta, _style)
 
 
 @order_target_percent.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order_target_percent(id_or_ins, percent, price=None, style=None):
+def stock_order_target_percent(id_or_ins, percent, price=None, style=None, price_or_style=None):
     account, position, ins = _get_account_position_ins(id_or_ins)
+    open_style, close_style = calc_open_close_style(price, style, price_or_style)
     if percent == 0:
-        return _submit_order(ins, position.closable, SIDE.SELL, POSITION_EFFECT.CLOSE, cal_style(price, style),
-                             position.quantity, False)
-    else:
-        return _order_value(
-            account, position, ins, account.total_value * percent - position.market_value, cal_style(price, style)
+        return _submit_order(
+            ins, position.closable, SIDE.SELL, POSITION_EFFECT.CLOSE, close_style, position.quantity, False
         )
+    _delta = account.total_value * percent - position.market_value
+    _style = open_style if _delta > 0 else close_style
+    return _order_value(account, position, ins, _delta, _style)
 
 
 @order.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order(order_book_id, quantity, price=None, style=None):
-    result_order = stock_order_shares(order_book_id, quantity, price, style)
+def stock_order(order_book_id, quantity, price=None, style=None, price_or_style=None):
+    result_order = stock_order_shares(order_book_id, quantity, price, style, price_or_style)
     if result_order:
         return [result_order]
     return []
 
 
 @order_to.register(INST_TYPE_IN_STOCK_ACCOUNT)
-def stock_order_to(order_book_id, quantity, price=None, style=None):
+def stock_order_to(order_book_id, quantity, price=None, style=None, price_or_style=None):
     position = Environment.get_instance().portfolio.get_position(order_book_id, POSITION_DIRECTION.LONG)
+    open_style, close_style = calc_open_close_style(price, style, price_or_style)
     quantity = quantity - position.quantity
-    result_order = stock_order_shares(order_book_id, quantity, price, style)
+    _style = open_style if quantity > 0 else close_style
+    result_order = stock_order_shares(order_book_id, quantity, price, _style, price_or_style)
     if result_order:
         return [result_order]
     return []
@@ -221,11 +241,9 @@ def stock_order_to(order_book_id, quantity, price=None, style=None):
     EXECUTION_PHASE.SCHEDULED,
     EXECUTION_PHASE.GLOBAL
 )
-@apply_rules(verify_that('id_or_ins').is_valid_stock(),
-             verify_that('amount').is_number(),
-             verify_that('style').is_instance_of((MarketOrder, LimitOrder, type(None))))
-def order_lots(id_or_ins, amount, price=None, style=None):
-    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> Optional[Order]
+@apply_rules(verify_that('id_or_ins').is_valid_stock(), verify_that('amount').is_number(), *common_rules)
+def order_lots(id_or_ins, amount, price=None, style=None, price_or_style=None):
+    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle], PRICE_OR_STYLE_TYPE) -> Optional[Order]
     """
     指定手数发送买/卖单。如有需要落单类型当做一个参量传入，如果忽略掉落单类型，那么默认是市价单（market order）。
 
@@ -233,6 +251,8 @@ def order_lots(id_or_ins, amount, price=None, style=None):
     :param int amount: 下单量, 正数代表买入，负数代表卖出。将会根据一手xx股来向下调整到一手的倍数，比如中国A股就是调整成100股的倍数。
     :param float price: 下单价格，默认为None，表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
     :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
+    :param price_or_style: 默认为None，表示市价单，可设置价格，表示限价单，也可以直接设置订单类型，有如下选项：MarketOrder、LimitOrder、
+                            TWAPOrder、VWAPOrder
 
     :example:
 
@@ -246,12 +266,15 @@ def order_lots(id_or_ins, amount, price=None, style=None):
     """
     auto_switch_order_value = Environment.get_instance().config.mod.sys_accounts.auto_switch_order_value
     account, position, ins = _get_account_position_ins(id_or_ins)
-    return _order_shares(ins, amount * int(ins.round_lot), cal_style(price, style), position.quantity,
-                         auto_switch_order_value)
+    return _order_shares(
+        ins, amount * int(ins.round_lot), cal_style(price, style, price_or_style), position.quantity,
+        auto_switch_order_value
+    )
 
 
 ORDER_TARGET_PORTFOLIO_SUPPORTED_INS_TYPES = {
-    INSTRUMENT_TYPE.CS, INSTRUMENT_TYPE.ETF, INSTRUMENT_TYPE.LOF, INSTRUMENT_TYPE.INDX}
+    INSTRUMENT_TYPE.CS, INSTRUMENT_TYPE.ETF, INSTRUMENT_TYPE.LOF, INSTRUMENT_TYPE.INDX
+}
 
 
 @export_as_api
@@ -263,28 +286,22 @@ def order_lots(id_or_ins, amount, price=None, style=None):
     EXECUTION_PHASE.GLOBAL
 )
 def order_target_portfolio(
-        target_portfolio: Dict[str, Union[float, Tuple[float, float], Tuple[float, float, float]]],
-        raise_exception_for_invalid_prices: bool = True
+        target_portfolio: Dict[str, float], price_or_styles: Dict[str, TUPLE_PRICE_OR_STYLE_TYPE] = dict({}),
 ) -> List[Order]:
     """
     批量调整股票仓位至目标权重。注意：股票账户中未出现在 target_portfolio 中的资产将被平仓！
 
-    该 API 的参数 target_portfolio 为字典，key 为 order_book_id 或 instrument，value 有三种数据类型可选：
-
-      * value 为权重。此时将根据股票最新价计算目标持仓数量并发出市价单调仓。
+    该 API 的参数 target_portfolio 为字典，key 为 order_book_id 或 instrument，value 为权重。
+    此时将根据参数 price_or_styles 中设置的价格来计算目标持仓数量并调仓。
 
-      * value 为权重和价格组成的 tuple。此时将根据该价格计算目标持仓数量并发出限价单（Signal 模式下将使用该价格撮合）。
-
-      * value 为权重、平仓价和开仓价组成的 tuple。此时将根据平仓价计算目标持仓数量并分别用两种价格发出平仓和开仓单。
-
-    :param target_portfolio: 目标权重字典，key 为 order_book_id，value 为权重或权重和价格组成的 tuple。
-    :param raise_exception_for_invalid_prices: 遇到无效的价格是否抛出异常。设为 False 表示遇到无效的价格时不交易该标的而不是抛出异常。
+    :param target_portfolio: 目标权重字典，key 为 order_book_id，value 为权重。
+    :param price_or_styles: 目标下单价格字典，key 为 order_book_id, value 为价格或订单类型或订单类型和价格组成的 tuple
 
     :example:
 
     .. code-block:: python
 
-        # 调整仓位，以使平安银行和万科 A 的持仓占比分别达到 10% 和 15%
+        # 调整仓位，以使平安银行和万科 A 的持仓占比分别达到 10% 和 15%, 同时发送市价单
         order_target_portfolio({
             '000001.XSHE': 0.1,
             '000002.XSHE': 0.15
@@ -292,22 +309,27 @@ def order_target_portfolio(
 
         # 调整仓位，分别以 14 和 26 元发出限价单，目标是使平安银行和万科 A 的持仓占比分别达到 10% 和 15%
         order_target_portfolio({
-            '000001.XSHE': (0.1, 14),
-            '000002.XSHE': (0.15, 26)
+            '000001.XSHE': 0.1,
+            '000002.XSHE': 0.15
+        }, {
+            '000001.XSHE': 14,
+            '000002.XSHE': 26,
         })
 
         # 调整仓位，使平安银行和万科 A 的持仓占比分别达到 10% 和 15%。
         # 其中平安银行的平仓价为 14 元，开仓价为 15 元；万科 A 的平仓价为 26 元，开仓价为 27 元。
         order_target_portfolio({
-            '000001.XSHE': (0.1, 14, 15),
-            '000002.XSHE': (0.15, 26, 27)
-
+            '000001.XSHE': 0.1,
+            '000002.XSHE': 0.15
+        }, {
+            '000001.XSHE': (15, 14),
+            '000002.XSHE': (27, 26)
+        })
 
     """
     env = Environment.get_instance()
-    # order_book_id -> (target_weight, close_price, open_price, last_price)
     target: Dict[str, Tuple[float, float, float, float]] = {}
-    for id_or_ins, target_quantity_price in target_portfolio.items():
+    for id_or_ins, percent in target_portfolio.items():
         ins = assure_instrument(id_or_ins)
         if not ins:
             raise RQInvalidArgument(_(
@@ -326,26 +348,16 @@ def order_target_portfolio(
             )
             continue
 
-        if isinstance(target_quantity_price, (int, float)):
-            target_percent = target_quantity_price
-            open_price = close_price = last_price
-        else:
-            target_percent, *target_prices = target_quantity_price
-            if not target_prices:
-                open_price = close_price = last_price
-            else:
-                try:
-                    close_price, open_price = target_prices
-                except ValueError:
-                    close_price = open_price = target_prices[0]
-
-        if target_percent < 0:
+        price_or_style = price_or_styles.get(ins.order_book_id)
+        open_style, close_style = calc_open_close_style(price=None, style=None, price_or_style=price_or_style)
+
+        if percent < 0:
             raise RQInvalidArgument(_(
                 "function order_target_portfolio: invalid values of target_portfolio, "
                 "excepted float between 0 and 1, got {} (key: {})"
-            ).format(target_percent, id_or_ins))
+            ).format(percent, id_or_ins))
 
-        target[order_book_id] = target_percent, close_price, open_price, last_price
+        target[order_book_id] = percent, open_style, close_style, last_price
 
     total_percent = sum(p for p, *__ in target.values())
     if total_percent > 1 and not np.isclose(total_percent, 1):
@@ -365,38 +377,32 @@ def order_target_portfolio(
 
     account_value = account.total_value
     close_orders, open_orders = [], []
-    for order_book_id, (target_percent, close_price, open_price, last_price) in target.items():
+    for order_book_id, (target_percent, open_style, close_style, last_price) in target.items():
+        open_price = _get_order_style_price(order_book_id, open_style)
+        close_price = _get_order_style_price(order_book_id, close_style)
         if not (is_valid_price(close_price) and is_valid_price(open_price)):
-            if raise_exception_for_invalid_prices:
-                raise RQInvalidArgument(_(
-                    "function order_target_portfolio: "
-                    "invalid close/open price {close_price}/{open_price} of {id_or_ins}"
-                ).format(id_or_ins=order_book_id, close_price=close_price, open_price=open_price))
-            else:
-                user_system_log.warn(_(
-                    "Adjust position of {id_or_ins} Failed: "
-                    "Invalid close/open price {close_price}/{open_price}").format(
-                        id_or_ins=order_book_id, close_price=close_price, open_price=open_price
-                    )
+            user_system_log.warn(_(
+                "Adjust position of {id_or_ins} Failed: "
+                "Invalid close/open price {close_price}/{open_price}").format(
+                    id_or_ins=order_book_id, close_price=close_price, open_price=open_price
                 )
-                continue
-        delta_quantity = (account_value * target_percent / (close_price or last_price)) \
-                         - current_quantities.get(order_book_id, 0)
+            )
+            continue
+
+        delta_quantity = (account_value * target_percent / close_price) - current_quantities.get(order_book_id, 0)
         delta_quantity = _round_order_quantity(env.data_proxy.instrument(order_book_id), delta_quantity)
         if delta_quantity == 0:
             continue
         elif delta_quantity > 0:
             quantity, side, position_effect = delta_quantity, SIDE.BUY, POSITION_EFFECT.OPEN
             order_list = open_orders
-            target_price = open_price
+            target_style = open_style
         else:
             quantity, side, position_effect = abs(delta_quantity), SIDE.SELL, POSITION_EFFECT.CLOSE
             order_list = close_orders
-            target_price = close_price
-        if target_price:
-            order = Order.__from_create__(order_book_id, quantity, side, LimitOrder(target_price), position_effect)
-        else:
-            order = Order.__from_create__(order_book_id, quantity, side, MarketOrder(), position_effect)
+            target_style = close_style
+        order = Order.__from_create__(order_book_id, quantity, side, target_style, position_effect)
+        if isinstance(target_style, MarketOrder):
             order.set_frozen_price(last_price)
         order_list.append(order)
 
diff --git a/rqalpha/mod/rqalpha_mod_sys_accounts/position_model.py b/rqalpha/mod/rqalpha_mod_sys_accounts/position_model.py
index e1aec9e02..1c944197e 100644
--- a/rqalpha/mod/rqalpha_mod_sys_accounts/position_model.py
+++ b/rqalpha/mod/rqalpha_mod_sys_accounts/position_model.py
@@ -297,7 +297,6 @@ def settlement(self, trading_date):
         data_proxy = self._env.data_proxy
         instrument = data_proxy.instrument(self._order_book_id)
         next_date = data_proxy.get_next_trading_date(trading_date)
-        delta_cash = self.equity
         if instrument.de_listed_at(next_date):
             user_system_log.warn(_(u"{order_book_id} is expired, close all positions by system").format(
                 order_book_id=self._order_book_id
@@ -307,7 +306,7 @@ def settlement(self, trading_date):
         if self._env.config.mod.sys_accounts.futures_settlement_price_type == "settlement":
             # 逐日盯市按照结算价结算
             self._last_price = self._env.data_proxy.get_settle_price(self._order_book_id, self._env.trading_dt)
-
+        delta_cash = self.equity
         self._avg_price = self.last_price
         return delta_cash
 
diff --git a/rqalpha/mod/rqalpha_mod_sys_analyser/report/report.py b/rqalpha/mod/rqalpha_mod_sys_analyser/report/report.py
index d0b7a27a5..ef16e8edd 100644
--- a/rqalpha/mod/rqalpha_mod_sys_analyser/report/report.py
+++ b/rqalpha/mod/rqalpha_mod_sys_analyser/report/report.py
@@ -145,7 +145,7 @@ def generate_report(result_dict, output_path):
             df = df.set_index("date")
 
         csv_txt = StringIO()
-        csv_txt.write(df.to_csv(encoding='utf-8', line_terminator='\n'))
+        csv_txt.write(df.to_csv(encoding='utf-8', lineterminator='\n'))
 
         with open(os.path.join(output_path, "{}.csv".format(name)), 'w') as csvfile:
             csvfile.write(csv_txt.getvalue())
diff --git a/rqalpha/mod/rqalpha_mod_sys_risk/validators/is_trading_validator.py b/rqalpha/mod/rqalpha_mod_sys_risk/validators/is_trading_validator.py
index c5351cbf4..46da9915e 100644
--- a/rqalpha/mod/rqalpha_mod_sys_risk/validators/is_trading_validator.py
+++ b/rqalpha/mod/rqalpha_mod_sys_risk/validators/is_trading_validator.py
@@ -19,6 +19,7 @@
 
 from rqalpha.utils.logger import user_system_log
 from rqalpha.utils.i18n import gettext as _
+from rqalpha.const import INSTRUMENT_TYPE
 
 
 class IsTradingValidator(AbstractFrontendValidator):
@@ -27,7 +28,7 @@ def __init__(self, env):
 
     def can_submit_order(self, order, account=None):
         instrument = self._env.data_proxy.instrument(order.order_book_id)
-        if not instrument.listing_at(self._env.trading_dt):
+        if instrument.type != INSTRUMENT_TYPE.INDX and not instrument.listing_at(self._env.trading_dt):
             user_system_log.warn(_(u"Order Creation Failed: {order_book_id} is not listing!").format(
                 order_book_id=order.order_book_id,
             ))
diff --git a/rqalpha/mod/rqalpha_mod_sys_simulation/matcher.py b/rqalpha/mod/rqalpha_mod_sys_simulation/matcher.py
index e92e6f085..a6cac6ae2 100644
--- a/rqalpha/mod/rqalpha_mod_sys_simulation/matcher.py
+++ b/rqalpha/mod/rqalpha_mod_sys_simulation/matcher.py
@@ -19,7 +19,7 @@
 from rqalpha.const import MATCHING_TYPE, ORDER_TYPE, POSITION_EFFECT, SIDE
 from rqalpha.environment import Environment
 from rqalpha.core.events import EVENT, Event
-from rqalpha.model.order import Order
+from rqalpha.model.order import Order, ALGO_ORDER_STYLES
 from rqalpha.model.trade import Trade
 from rqalpha.model.tick import TickObject
 from rqalpha.portfolio.account import Account
@@ -83,6 +83,26 @@ def _open_auction_deal_price_decider(self, order_book_id, _):
     SUPPORT_POSITION_EFFECTS = (POSITION_EFFECT.OPEN, POSITION_EFFECT.CLOSE, POSITION_EFFECT.CLOSE_TODAY)
     SUPPORT_SIDES = (SIDE.BUY, SIDE.SELL)
 
+    def _get_bar_volume(self, order, open_auction=False):
+        if open_auction:
+            volume = self._env.data_proxy.get_open_auction_bar(order.order_book_id, self._env.calendar_dt).volume
+        else:
+            if isinstance(order.style, ALGO_ORDER_STYLES):
+                _, volume = self._env.data_proxy.get_algo_bar(order.order_book_id, order.style, self._env.calendar_dt)
+            else:
+                volume = self._env.get_bar(order.order_book_id).volume
+        return volume
+
+    def _get_deal_price(self, order, open_auction=False):
+        if open_auction:
+            deal_price = self._open_auction_deal_price_decider(order.order_book_id, order.side)
+        else:
+            if isinstance(order.style, ALGO_ORDER_STYLES):
+                deal_price, v = self._env.data_proxy.get_algo_bar(order.order_book_id, order.style, self._env.calendar_dt)
+            else:
+                deal_price = self._deal_price_decider(order.order_book_id, order.side)
+        return deal_price
+
     def match(self, account, order, open_auction):
         # type: (Account, Order, bool) -> None
         if not (order.position_effect in self.SUPPORT_POSITION_EFFECTS and order.side in self.SUPPORT_SIDES):
@@ -90,10 +110,7 @@ def match(self, account, order, open_auction):
         order_book_id = order.order_book_id
         instrument = self._env.get_instrument(order_book_id)
 
-        if open_auction:
-            deal_price = self._open_auction_deal_price_decider(order_book_id, order.side)
-        else:
-            deal_price = self._deal_price_decider(order_book_id, order.side)
+        deal_price = self._get_deal_price(order, open_auction)
 
         if not is_valid_price(deal_price):
             listed_date = instrument.listed_date.date()
@@ -104,6 +121,8 @@ def match(self, account, order, open_auction):
                     order_book_id=order.order_book_id,
                     listed_date=listed_date,
                 )
+            elif isinstance(order.style, ALGO_ORDER_STYLES):
+                reason = _(u"Order Cancelled: {order_book_id} bar no volume").format(order_book_id=order.order_book_id)
             else:
                 reason = _(u"Order Cancelled: current bar [{order_book_id}] miss market data.").format(
                     order_book_id=order.order_book_id)
@@ -138,17 +157,14 @@ def match(self, account, order, open_auction):
                     return
 
         if self._inactive_limit:
-            bar_volume = self._env.get_bar(order_book_id).volume
+            bar_volume = self._get_bar_volume(order, open_auction=open_auction)
             if bar_volume == 0:
                 reason = _(u"Order Cancelled: {order_book_id} bar no volume").format(order_book_id=order.order_book_id)
                 order.mark_cancelled(reason)
                 return
 
         if self._volume_limit:
-            if open_auction:
-                volume = self._env.data_proxy.get_open_auction_bar(order_book_id, self._env.calendar_dt).volume
-            else:
-                volume = self._env.get_bar(order_book_id).volume
+            volume = self._get_bar_volume(order, open_auction=open_auction)
             if volume == volume:
                 volume_limit = round(volume * self._volume_percent) - self._turnover[order.order_book_id]
 
@@ -171,6 +187,7 @@ def match(self, account, order, open_auction):
             fill = order.unfilled_quantity
 
         ct_amount = account.calc_close_today_amount(order_book_id, fill, order.position_direction)
+
         if open_auction:
             price = deal_price
         else:
diff --git a/rqalpha/mod/rqalpha_mod_sys_simulation/mod.py b/rqalpha/mod/rqalpha_mod_sys_simulation/mod.py
index a72f8462e..4c021a91f 100644
--- a/rqalpha/mod/rqalpha_mod_sys_simulation/mod.py
+++ b/rqalpha/mod/rqalpha_mod_sys_simulation/mod.py
@@ -73,6 +73,9 @@ def start_up(self, env, mod_config):
         event_source = SimulationEventSource(env)
         env.set_event_source(event_source)
 
+        from .validator import OrderStyleValidator
+        env.add_frontend_validator(OrderStyleValidator(env.config.base.frequency))
+
     def tear_down(self, code, exception=None):
         pass
 
diff --git a/rqalpha/mod/rqalpha_mod_sys_simulation/signal_broker.py b/rqalpha/mod/rqalpha_mod_sys_simulation/signal_broker.py
index 9d66f2a7d..832c75f37 100644
--- a/rqalpha/mod/rqalpha_mod_sys_simulation/signal_broker.py
+++ b/rqalpha/mod/rqalpha_mod_sys_simulation/signal_broker.py
@@ -18,12 +18,15 @@
 
 from copy import copy
 
+import numpy as np
+
 from rqalpha.interface import AbstractBroker
 from rqalpha.utils.logger import user_system_log
 from rqalpha.utils.i18n import gettext as _
 from rqalpha.utils import is_valid_price
 from rqalpha.core.events import EVENT, Event
 from rqalpha.model.trade import Trade
+from rqalpha.model.order import ALGO_ORDER_STYLES
 from rqalpha.const import SIDE, ORDER_TYPE, POSITION_EFFECT
 
 from .slippage import SlippageDecider
@@ -77,6 +80,12 @@ def _match(self, account, order):
 
         if order.type == ORDER_TYPE.LIMIT:
             deal_price = order.frozen_price
+        elif isinstance(order.style, ALGO_ORDER_STYLES):
+            deal_price, v = self._env.data_proxy.get_algo_bar(order.order_book_id, order.style, self._env.calendar_dt)
+            if np.isnan(deal_price):
+                reason = _(u"Order Cancelled: {order_book_id} bar no volume").format(order_book_id=order.order_book_id)
+                order.mark_rejected(reason)
+                return
         else:
             deal_price = last_price
 
diff --git a/rqalpha/mod/rqalpha_mod_sys_simulation/simulation_broker.py b/rqalpha/mod/rqalpha_mod_sys_simulation/simulation_broker.py
index 98ec53b1c..48ae65334 100644
--- a/rqalpha/mod/rqalpha_mod_sys_simulation/simulation_broker.py
+++ b/rqalpha/mod/rqalpha_mod_sys_simulation/simulation_broker.py
@@ -166,7 +166,7 @@ def on_tick(self, event):
         self._match(tick.order_book_id)
 
     def _match(self, order_book_id=None):
-        order_filter = None if order_book_id is None else lambda a_and_o: a_and_o[1].order_book_id == order_book_id
+        order_filter = lambda a_and_o: not (a_and_o[1].is_final() or (order_book_id and a_and_o[1].order_book_id != order_book_id))
         for account, order in filter(order_filter, self._open_orders):
             self._get_matcher(order.order_book_id).match(account, order, open_auction=False)
         for account, order in filter(order_filter, self._open_auction_orders):
diff --git a/rqalpha/mod/rqalpha_mod_sys_simulation/validator.py b/rqalpha/mod/rqalpha_mod_sys_simulation/validator.py
new file mode 100644
index 000000000..9df8ff3b2
--- /dev/null
+++ b/rqalpha/mod/rqalpha_mod_sys_simulation/validator.py
@@ -0,0 +1,18 @@
+
+from rqalpha.model.order import ALGO_ORDER_STYLES
+from rqalpha.interface import AbstractFrontendValidator
+
+
+class OrderStyleValidator(AbstractFrontendValidator):
+
+    def __init__(self, frequency):
+        self._frequency = frequency
+
+    def can_submit_order(self, order, account=None):
+        if isinstance(order.style, ALGO_ORDER_STYLES) and self._frequency in ["1m", "tick"]:
+            raise RuntimeError("algo order no support 1m or tick frequency")
+        return True
+
+    def can_cancel_order(self, order, account=None):
+        return True
+
diff --git a/rqalpha/mod/rqalpha_mod_sys_transaction_cost/__init__.py b/rqalpha/mod/rqalpha_mod_sys_transaction_cost/__init__.py
index 9a0b4de33..fd5c8925f 100644
--- a/rqalpha/mod/rqalpha_mod_sys_transaction_cost/__init__.py
+++ b/rqalpha/mod/rqalpha_mod_sys_transaction_cost/__init__.py
@@ -18,9 +18,11 @@
 __config__ = {
     # 股票最小手续费，单位元
     "cn_stock_min_commission": 5,
-    # 佣金倍率，即在默认的手续费率基础上按该倍数进行调整，股票的默认佣金为万八，期货默认佣金因合约而异
+    # 佣金倍率（即将废弃）
     "commission_multiplier": None,
+    # 股票佣金倍率,即在默认的手续费率基础上按该倍数进行调整，股票的默认佣金为万八
     "stock_commission_multiplier": 1,
+    # 期货佣金倍率,即在默认的手续费率基础上按该倍数进行调整，期货默认佣金因合约而异
     "futures_commission_multiplier": 1,
     # 印花倍率，即在默认的印花税基础上按该倍数进行调整，股票默认印花税为千分之一，单边收取
     "tax_multiplier": 1,
diff --git a/rqalpha/mod/rqalpha_mod_sys_transaction_cost/mod.py b/rqalpha/mod/rqalpha_mod_sys_transaction_cost/mod.py
index 854d94152..5cc56e1c4 100644
--- a/rqalpha/mod/rqalpha_mod_sys_transaction_cost/mod.py
+++ b/rqalpha/mod/rqalpha_mod_sys_transaction_cost/mod.py
@@ -27,7 +27,7 @@
 
 class TransactionCostMod(AbstractMod):
     def start_up(self, env, mod_config):
-        if mod_config.commission_multiplier:
+        if mod_config.commission_multiplier is not None:
             stock_commission_multiplier = mod_config.commission_multiplier
             futures_commission_multiplier = mod_config.commission_multiplier
             user_log.warning(
diff --git a/rqalpha/model/order.py b/rqalpha/model/order.py
index 12191b718..dde9b1a04 100644
--- a/rqalpha/model/order.py
+++ b/rqalpha/model/order.py
@@ -20,7 +20,7 @@
 
 import numpy as np
 
-from rqalpha.const import ORDER_STATUS, ORDER_TYPE, SIDE, POSITION_EFFECT, POSITION_DIRECTION
+from rqalpha.const import ORDER_STATUS, ORDER_TYPE, SIDE, POSITION_EFFECT, POSITION_DIRECTION, ALGO
 from rqalpha.utils import id_gen, decimal_rounding_floor, get_position_direction
 from rqalpha.utils.repr import property_repr, properties
 from rqalpha.utils.logger import user_system_log
@@ -50,6 +50,7 @@ def __init__(self):
         self._type = None
         self._avg_price = None
         self._transaction_cost = None
+        self._style = None
         self._kwargs = {}
 
     @staticmethod
@@ -109,14 +110,19 @@ def __from_create__(cls, order_book_id, quantity, side, style, position_effect,
         order._message = ""
         order._filled_quantity = 0
         order._status = ORDER_STATUS.PENDING_NEW
+        order._style = style
         if isinstance(style, LimitOrder):
             if env.config.base.round_price:
                 tick_size = env.data_proxy.get_tick_size(order_book_id)
                 style.round_price(tick_size)
             order._frozen_price = style.get_limit_price()
             order._type = ORDER_TYPE.LIMIT
+        elif isinstance(style, ALGO_ORDER_STYLES):
+            algo_price, _ = env.data_proxy.get_algo_bar(order_book_id, style, env.calendar_dt)
+            order._frozen_price = env.get_last_price(order_book_id) if np.isnan(algo_price) else algo_price
+            order._type = ORDER_TYPE.ALGO
         else:
-            order._frozen_price = 0.
+            order._frozen_price = env.get_last_price(order_book_id)
             order._type = ORDER_TYPE.MARKET
         order._avg_price = 0
         order._transaction_cost = 0
@@ -237,6 +243,13 @@ def type(self):
         """
         return self._type
 
+    @property
+    def style(self):
+        """
+        [ORDER_STYLE] 订单类型
+        """
+        return self._style
+
     @property
     def avg_price(self):
         """
@@ -338,6 +351,27 @@ def get_limit_price(self):
         raise NotImplementedError
 
 
+class AlgoOrder(OrderStyle):
+    __repr__ = ORDER_TYPE.ALGO.__repr__
+
+    def __init__(self, start_min, end_min):
+        self.start_min = start_min
+        self.end_min = end_min
+
+    def get_limit_price(self):
+        return None
+
+
+class TWAPOrder(AlgoOrder):
+    TYPE = ALGO.TWAP
+    __repr__ = ALGO.TWAP.__repr__
+
+
+class VWAPOrder(AlgoOrder):
+    TYPE = ALGO.VWAP
+    __repr__ = ALGO.VWAP.__repr__
+
+
 class MarketOrder(OrderStyle):
     __repr__ = ORDER_TYPE.MARKET.__repr__
 
@@ -362,3 +396,7 @@ def round_price(self, tick_size):
                 self.limit_price = float((limit_price_decimal / tick_size_decimal).to_integral() * tick_size_decimal)
         else:
             user_system_log.warn('Invalid tick size: {}'.format(tick_size))
+
+
+ALGO_ORDER_STYLES = (VWAPOrder, TWAPOrder)
+ALL_ORDER_STYPES = (LimitOrder, MarketOrder, TWAPOrder, VWAPOrder)
diff --git a/rqalpha/portfolio/account.py b/rqalpha/portfolio/account.py
index 13654fee1..8cf1ac378 100644
--- a/rqalpha/portfolio/account.py
+++ b/rqalpha/portfolio/account.py
@@ -318,7 +318,7 @@ def _on_before_trading(self, _):
                 del self._positions[order_book_id]
 
         trading_date = self._env.trading_dt.date()
-        while self._pending_deposit_withdraw and self._pending_deposit_withdraw[0][0] <= trading_date:
+        while self._pending_deposit_withdraw and self._pending_deposit_withdraw[0][0].date() <= trading_date:
             _, amount = self._pending_deposit_withdraw.pop(0)
             self._total_cash += amount
 
diff --git a/rqalpha/utils/__init__.py b/rqalpha/utils/__init__.py
index b9c693aaf..dc6fcc9c8 100644
--- a/rqalpha/utils/__init__.py
+++ b/rqalpha/utils/__init__.py
@@ -236,3 +236,8 @@ def get_trading_period(universe, accounts):
     from rqalpha.environment import Environment
     trading_period = STOCK_TRADING_PERIOD if DEFAULT_ACCOUNT_TYPE.STOCK in accounts else []
     return Environment.get_instance().data_proxy.get_trading_period(universe, trading_period)
+
+
+def safe_div(dividend, divisor):
+    return dividend / divisor if divisor else np.nan
+
diff --git a/rqalpha/utils/arg_checker.py b/rqalpha/utils/arg_checker.py
index b96c094b9..ec7a0c55d 100644
--- a/rqalpha/utils/arg_checker.py
+++ b/rqalpha/utils/arg_checker.py
@@ -31,6 +31,7 @@
 from rqalpha.utils import unwrapper, INST_TYPE_IN_STOCK_ACCOUNT
 from rqalpha.utils.i18n import gettext as _
 from rqalpha.utils.exception import patch_system_exc, EXC_EXT_NAME
+from rqalpha.utils.logger import user_system_log
 
 
 main_contract_warning_flag = True
@@ -141,6 +142,14 @@ def is_number(self):
         self._rules.append(self._is_number)
         return self
 
+    def deprecated(self, hint="deprecated"):
+        def inner(func_name, value):
+            if value is not None:
+                content = "{} param {} is deprecated. {}".format(func_name, self._arg_name, hint)
+                user_system_log.warning(content)
+        self._rules.append(inner)
+        return self
+
     def is_in(self, valid_values, ignore_none=True):
         def check_is_in(func_name, value):
             if ignore_none and value is None:
@@ -236,7 +245,7 @@ def check_is_valid_date(func_name, value):
 
     def is_greater_or_equal_than(self, low):
         def check_greater_or_equal_than(func_name, value):
-            if value < low:
+            if isinstance(value, (int, float)) and value < low:
                 raise RQInvalidArgument(
                     _(u"function {}: invalid {} argument, expect a value >= {}, got {} (type: {})").format(
                         func_name, self._arg_name, low, value, type(value)
@@ -246,7 +255,7 @@ def check_greater_or_equal_than(func_name, value):
 
     def is_greater_than(self, low):
         def check_greater_than(func_name, value):
-            if value <= low:
+            if isinstance(value, (int, float)) and value <= low:
                 raise RQInvalidArgument(
                     _(u"function {}: invalid {} argument, expect a value > {}, got {} (type: {})").format(
                         func_name, self._arg_name, low, value, type(value)
@@ -256,7 +265,7 @@ def check_greater_than(func_name, value):
 
     def is_less_or_equal_than(self, high):
         def check_less_or_equal_than(func_name, value):
-            if value > high:
+            if isinstance(value, (int, float)) and value > high:
                 raise RQInvalidArgument(
                     _(u"function {}: invalid {} argument, expect a value <= {}, got {} (type: {})").format(
                         func_name, self._arg_name, high, value, type(value)
@@ -267,7 +276,7 @@ def check_less_or_equal_than(func_name, value):
 
     def is_less_than(self, high):
         def check_less_than(func_name, value):
-            if value >= high:
+            if isinstance(value, (int, float)) and value >= high:
                 raise RQInvalidArgument(
                     _(u"function {}: invalid {} argument, expect a value < {}, got {} (type: {})").format(
                         func_name, self._arg_name, high, value, type(value)
diff --git a/rqalpha/utils/datetime_func.py b/rqalpha/utils/datetime_func.py
index 2ad0ba2c2..45fb85856 100644
--- a/rqalpha/utils/datetime_func.py
+++ b/rqalpha/utils/datetime_func.py
@@ -32,8 +32,8 @@ def convert_date_to_date_int(dt):
 
 
 def convert_date_to_int(dt):
-    t = dt.year * 10000 + dt.month * 100 + dt.day
-    t *= 1000000
+    # 原先的写法在pandas2.0下会被转化为int32类型导致精度丢失
+    t = dt.year * 10000000000 + dt.month * 100000000 + dt.day * 1000000
     return t
 
 
diff --git a/setup.cfg b/setup.cfg
index 466ea5ec8..4499ebdf9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,7 +5,7 @@
 
 [metadata]
 name = rqalpha
-version = 4.16.2
+version = 5.0.0
 
 [versioneer]
 VCS = git
diff --git a/setup.py b/setup.py
index e766edc09..7d1623c36 100644
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@
 requirements = [
     'requests',
     'numpy',
-    'pandas >=1.0.5, <2.0.0',
+    'pandas >=1.0.5',
     'python-dateutil',
     'six',
     'logbook',


Test patch:
diff --git a/test.py b/test.py
index 7ae3f9ca3..cde4a5da3 100644
--- a/test.py
+++ b/test.py
@@ -109,7 +109,7 @@ def run_test(filename):
         except:
             pass
         try:
-            assert_frame_equal(df, old_df, check_less_precise=8)
+            assert_frame_equal(df, old_df, atol=1e-8, rtol=1e-5)
         except AssertionError as e:
             return str(e)
 
diff --git a/tests/api_tests/test_api_stock.py b/tests/api_tests/test_api_stock.py
index 45984072e..e30f8e30f 100644
--- a/tests/api_tests/test_api_stock.py
+++ b/tests/api_tests/test_api_stock.py
@@ -166,9 +166,13 @@ def handle_bar(context, bar_dict):
             assert get_position("000004.XSHE").quantity == 10500  # (1000000 * 0.2) / 18.92 = 10570.82
         elif context.counter == 2:
             order_target_portfolio({
-                "000004.XSHE": (0.1, 18, 18.5),
-                "000005.XSHE": (0.2, 2.92),
-                "600519.XSHG": (0.6, 980, 970),
+                "000004.XSHE": 0.1,
+                "000005.XSHE": 0.2,
+                "600519.XSHG": 0.6,
+            }, {
+                "000004.XSHE": (18.5, 18),
+                "000005.XSHE": (2.92, ),
+                "600519.XSHG": (970, 980),
             })
             assert get_position("000001.XSHE").quantity == 0  # 清仓
             assert get_position("000004.XSHE").quantity == 5600  # (993695.7496 * 0.1) / 18 = 5520.53
@@ -201,8 +205,11 @@ def handle_bar(context, handle_bar):
         context.counter += 1
         if context.counter == 1:
             order_target_portfolio({
-                "000001.XSHE": (0.1, 14),
-                "000004.XSHE": (0.2, 10),
+                "000001.XSHE": 0.1,
+                "000004.XSHE": 0.2,
+            }, {
+                "000001.XSHE": 14,
+                "000004.XSHE": 10,
             })
             assert get_position("000001.XSHE").quantity == 7100   # (1000000 * 0.1) / 14.37 = 7142.86
             assert get_position("000004.XSHE").quantity == 0  # 价格低过跌停价，被拒单
diff --git a/tests/outs/test_f_buy_and_hold.pkl b/tests/outs/test_f_buy_and_hold.pkl
index d569a8f01..56356fea9 100644
Binary files a/tests/outs/test_f_buy_and_hold.pkl and b/tests/outs/test_f_buy_and_hold.pkl differ
diff --git a/tests/outs/test_f_macd.pkl b/tests/outs/test_f_macd.pkl
index 6e3bbe22c..a97cffa67 100644
Binary files a/tests/outs/test_f_macd.pkl and b/tests/outs/test_f_macd.pkl differ
diff --git a/tests/outs/test_f_macd_signal.pkl b/tests/outs/test_f_macd_signal.pkl
index f88f1e179..cbe7ffe0e 100644
Binary files a/tests/outs/test_f_macd_signal.pkl and b/tests/outs/test_f_macd_signal.pkl differ
diff --git a/tests/outs/test_f_mean_reverting.pkl b/tests/outs/test_f_mean_reverting.pkl
index f0400d7fa..e820ee9fa 100644
Binary files a/tests/outs/test_f_mean_reverting.pkl and b/tests/outs/test_f_mean_reverting.pkl differ
diff --git a/tests/outs/test_s_buy_and_hold.pkl b/tests/outs/test_s_buy_and_hold.pkl
index 9a48a5888..72f5d845a 100644
Binary files a/tests/outs/test_s_buy_and_hold.pkl and b/tests/outs/test_s_buy_and_hold.pkl differ
diff --git a/tests/outs/test_s_dual_thrust.pkl b/tests/outs/test_s_dual_thrust.pkl
index 5e4abb5db..5a31ca312 100644
Binary files a/tests/outs/test_s_dual_thrust.pkl and b/tests/outs/test_s_dual_thrust.pkl differ
diff --git a/tests/outs/test_s_scheduler.pkl b/tests/outs/test_s_scheduler.pkl
index e3e8acea2..75820ba27 100644
Binary files a/tests/outs/test_s_scheduler.pkl and b/tests/outs/test_s_scheduler.pkl differ
diff --git a/tests/outs/test_s_tick_size.pkl b/tests/outs/test_s_tick_size.pkl
index 035ba825a..436386115 100644
Binary files a/tests/outs/test_s_tick_size.pkl and b/tests/outs/test_s_tick_size.pkl differ
diff --git a/tests/outs/test_s_turtle.pkl b/tests/outs/test_s_turtle.pkl
index fec55aa14..e45592842 100644
Binary files a/tests/outs/test_s_turtle.pkl and b/tests/outs/test_s_turtle.pkl differ
diff --git a/tests/outs/test_s_turtle_signal.pkl b/tests/outs/test_s_turtle_signal.pkl
index ec4225adf..6ecb1f4a9 100644
Binary files a/tests/outs/test_s_turtle_signal.pkl and b/tests/outs/test_s_turtle_signal.pkl differ
diff --git a/tests/outs/test_sf_buy_and_hold.pkl b/tests/outs/test_sf_buy_and_hold.pkl
index a38894931..c186e0f3f 100644
Binary files a/tests/outs/test_sf_buy_and_hold.pkl and b/tests/outs/test_sf_buy_and_hold.pkl differ