return self._priceToDependOn        

exec wrapper2("Dependency", 
             """ Dependent price strategy believes that the fair price of an asset *A* 
                 is completely correlated with price of another asset *B* and the following relation 
                 should be held: *PriceA* = *kPriceB*, where *k* is some factor. 
                 It may be considered as a variety of a fundamental value strategy 
                 with the exception that it is invoked every the time price of another
                 asset *B* changes. 
             
                 It has following parameters: 
                 
                 |orderFactory| 
                     order factory function (default: order.Market.T)
                 
                 |bookToDependOn| 
                     reference to order book for another asset used to evaluate fair price of our asset
                 
                 |factor| 
                     multiplier to obtain fair asset price from the reference asset price
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)
             """,
             [('bookToDependOn','None',                             'IOrderBook'),
              ('orderFactory',  'order.MarketFactory',              'Side -> Volume -> IOrder'),
              ('factor',        '1.',                               'positive'),
              ('volumeDistr',   'mathutils.rnd.expovariate(.1)',    '() -> Volume')], register=False)

        
from marketsim import event, meta, types, registry, _

from _basic import Strategy, Empty
from _wrap import wrapper2

class _Array_Impl(Strategy):
    
    def __init__(self):
        Strategy.__init__(self)
        for s in self.strategies:
            event.subscribe(s.on_order_created, _(self)._send, self)
    
    def dispose(self):
        for s in self.strategies:
            s.dispose()

exec wrapper2('Array', "", [('strategies', '[Empty()]', 'meta.listOf(types.ISingleAssetStrategy)')])
                                                      oppositePrice, 
                                                      volumeToTrade)                                    
                                    ))
                    
    def _send(self, orderbook, order):
        for t in self._traders:
            if t.orderBook == orderbook:
                t.send(order)
                    
    def _schedule(self, side, queue):
        self._scheduler.scheduleAfter(0, bind.Method(self, 'inner', queue, side))
    
    def bind(self, context):
        self._traders = [t for t in self._trader.traders]
        self._books = [t.orderBook for t in self._trader.traders]        
                        
        def regSide(side):
            for book in self._books:
                queue = book.queue(side) 
                event.subscribe(queue.on_best_changed, 
                                bind.Method(self, '_schedule', side), 
                                self).bind(None)
                if not queue.empty:
                    self._bests[side.id][queue.best.signedPrice] = queue
                    self._oldBests[queue] = queue.best.signedPrice
                    
        regSide(Side.Buy)
        regSide(Side.Sell)

exec wrapper2("Arbitrage", "", [], register=False)
     
    def __init__(self):                
        Strategy.__init__(self)
        event.subscribe(self.eventGen, _(self)._wakeUp, self)
         
    def __repr__(self):
        return "Generic(%s, %s)" % (self.eventGen, self.orderFactory)
         
    def _wakeUp(self, _):
        # determine side and parameters of an order to create
        order = self.orderFactory()
        # send order to the order book
        if order is not None:
            self._send(order)
 
exec  wrapper2("Generic", 
             """ Generic strategy that wakes up on events given by *eventGen*, 
                 creates an order via *orderFactory* and sends the order to the market using its trader
              
                 Parameters:
                  
                     |orderFactory|
                         order factory function (default: order.Limit.T)
                          
                     |eventGen|
                         Event source making the strategy to wake up
                          
             """,
              [('orderFactory',         'order.factory.Market()',               'types.IOrderGenerator'),
               ('eventGen',             'event.Every(ops.constant(1.))',    'IEvent')])
@sig(args=(ISingleAssetTrader,), rv=ISingleAssetTrader)
def efficiencyTrend(trader):
    """ Returns derivative of a *trader*'s "cleared" balance
    """
    return observable.trend(observable.Efficiency(trader), alpha=0.065)

@registry.expose(alias=['Virtual market orders with unit volume'])
@sig(args=(ISingleAssetStrategy,), rv=ISingleAssetStrategy)
def virtualWithUnitVolume(strategy):
    """ Creates for a *strategy* a clone with same parameters but sending virtual market orders of unit volume
    """
    return strategy.With(volumeDistr=mathutils.constant(1), orderFactory=order.VirtualMarketFactory)    

exec wrapper2("tradeIfProfitable", 
             "",
             [('strategy',   'FundamentalValue()',    'ISingleAssetStrategy'), 
              ('efficiency', 'efficiencyTrend',       'ISingleAssetTrader -> ISingleAssetTrader'),
              ('estimator',  'virtualWithUnitVolume', 'ISingleAssetStrategy -> ISingleAssetStrategy')], register=False)

        
@registry.expose(['Adaptive', 'TradeIfProfitable'])
class TradeIfProfitable(tradeIfProfitable):
    """ Strategy that estimates efficiency of original *strategy* 
    (normally as derivative of "cleared" balance for its clone sending unit volume orders)
    
    Parameters: 
    
        |strategy| 
            original strategy that can be suspended
            
        |efficiency| 
                # create order given side and parameters
                order = self.orderFactory(side)(volume)
                # send order to the order book
                self._trader.send(order)

exec  wrapper2("Generic", 
             """ Generic strategy that wakes up on events given by *eventGen*, 
                 chooses side of order to create using *sideFunc* and its volume by *volumeFunc*,
                 creates an order via *orderFactory* and sends the order to the market using its trader
             
                 Parameters:
                 
                     |orderFactory|
                         order factory function (default: order.Limit.T)
                         
                     |eventGen|
                         Event source making the strategy to wake up
                         
                     |volumeFunc|
                         defines volumes of orders to create 
                         (default: exponential distribution with |lambda| = 1)
                         
                     |sideFunc|
                         function choosing side of order to create (default: randomSide)
                         
             """,
              [('orderFactory',         'order.MarketFactory',                  'Side -> Volume -> IOrder'),
               ('eventGen',             'None',                                 'Event'),
               ('volumeFunc',           'mathutils.rnd.expovariate(1.)',        '() -> Volume'),
               ('sideFunc',             'randomSide',                           '() -> Side')], register=False)
Exemple #7
0
    def _fundamentalValue(self):
        return self.fundamentalValue  

exec  wrapper2("FundamentalValue", 
             """ Fundamental value strategy believes that an asset should have some specific price 
                 (*fundamental value*) and if the current asset price is lower than the fundamental value 
                 it starts to buy the asset and if the price is higher it starts to sell the asset. 
             
                 It has following parameters: 
                 
                 |orderFactory| 
                     order factory function (default: order.Market.T)
                 
                 |creationIntervalDistr| 
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)
                 
                 |fundamentalValue| 
                     defines fundamental value (default: constant 100)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)
             """,
              [('orderFactory',         'order.MarketFactory',          'Side -> Volume -> IOrder'),
               ('fundamentalValue',     'mathutils.constant(100)',      '() -> Price'),
               ('volumeDistr',          'mathutils.rnd.expovariate(1.)','() -> Volume'),
               ('creationIntervalDistr','mathutils.rnd.expovariate(1.)','() -> TimeInterval')])

from _lp_side import ConstantSide
from _signal import ConditionSide, less_float, none_side
            yield strategy
            yield efficiency
            yield estimator_strategy
        
    def suspend(self, s=True):
        Strategy.suspend(self, s)
        if self._current:
            self._current.suspend(s)
        for (_, _, estimator_strategy, _) in self._strategies:
            estimator_strategy.suspend(s)
            
exec wrapper2("ChooseTheBest",
             """ A composite strategy initialized with an array of strategies. 
                 In some moments of time the most effective strategy 
                 is chosen and made running; other strategies are suspended.
                 
                 Parameters: 
                
                     |strategies| 
                        original strategies that can be suspended
                     
                     |efficiency| 
                         function estimating is the strategy efficient or not
                     
                     |estimator| 
                        function creating phantom strategy used for efficiency estimation
                 
                 """,
             [('strategies',  '[FundamentalValue()]',   'meta.listOf(ISingleAssetStrategy)'),
              ('efficiency',  'efficiencyTrend',        'ISingleAssetTrader -> ISingleAssetTrader'),
              ('estimator',   'virtualWithUnitVolume',  'ISingleAssetStrategy -> ISingleAssetStrategy')], category="Adaptive")
Exemple #9
0
        
    def _orderFunc(self):
        conv = types.Side.byId
        return (types.Side.byId(self.sideDistr()), (int(self.volumeDistr()),)) 

exec wrapper2("Noise", 
             """ Noise strategy is a quite dummy strategy that randomly creates an order 
                 and sends it to the order book. 
                 
                 It has following parameters:

                 |orderFactoryT| 
                     order factory function (default: order.Market.T)

                 |creationIntervalDistr| 
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)
                     
                 |sideDistr| 
                     side of orders to create 
                     (default: discrete uniform distribution P(Sell)=P(Buy)=.5)
             """,
             [("orderFactory",          "order.MarketFactory",          'Side -> Volume -> IOrder'),
              ("sideDistr",             "mathutils.rnd.randint(0,1)",   "() -> int"), # in fact it should be () -> Side
              ("volumeDistr",           "mathutils.rnd.expovariate(1.)",'() -> Volume'),
              ("creationIntervalDistr", "mathutils.rnd.expovariate(1.)",'() -> TimeInterval')])

@registry.expose(["Generic", "Noise"], args = ())
def NoiseEx     (orderFactory           = order.MarketFactory,
                 sideDistr              = randomSide, 
                 volumeDistr            = mathutils.rnd.expovariate(1.), 
                # it converges since every time we pops an element from the queue
                self._elements.pop()
            else:
                # if order is valid, cancel it
                self._book.process(request.Cancel(e))
                return

    def __init__(self):

        # orders created by trader
        self._elements = []
        self._eventGen = event.Every(self.cancellationIntervalDistr)
        self._myTrader = trader.SingleProxy()
        self._book = orderbook.OfTrader(self._myTrader)
        self.on_order_created = event.Event()
        
    _internals = ['_myTrader']

    def bind(self, ctx):
        event.subscribe(self._myTrader.on_order_sent, _(self).process, self, ctx)
        event.subscribe(self._eventGen, _(self)._wakeUp, self, ctx)
        
    def process(self, order):
        """ Puts 'order' to future cancellation list
        """
        self._elements.append(order)

exec wrapper2("Canceller",
             "",
             [('cancellationIntervalDistr', 'mathutils.rnd.expovariate(1.)',    '() -> TimeInterval')])
        self._eventGen = event.Every(ops.constant(0.9))
        event.subscribe(self._eventGen, _(self)._wakeUp, self)

        self.book = orderbook.OfTrader()
        self.midprice = observable.MidPrice(self.book)
        self.log = TraderHistory(SingleProxy())
        self.prev_mid = None

    _internals = ['book', 'log', 'midprice']

    def _wakeUp(self, dummy):
        for position in self.log.pending:
                self._trader.send(request.Cancel(position))

        mid = self.midprice()

        if mid is not None:
            bid = mid+1-(self.log.amount/self.volume)
            ask = mid-1-(self.log.amount/self.volume)
            buyOrder = order.LimitFactory(Side.Buy)(bid, self.volume)
            sellOrder = order.LimitFactory(Side.Sell)(ask, self.volume)
            self._send(buyOrder)
            self._send(sellOrder)

exec  wrapper2("MarketMaker",
             """

             |volume|
                Volume of Buy/Sell orders. Should be large compared to the volumes of other traders.
             """,
              [ ('volume', '20.', 'Volume') ], register=False)
exec wrapper2(
    "MultiarmedBandit",
    """ A composite strategy initialized with an array of strategies. 
                 In some moments of time the most effective strategy 
                 is chosen and made running; other strategies are suspended.
                 The choice is made randomly among the strategies that have
                 a positive efficiency trend, weighted by the efficiency value.
                 
                 Parameters: 
                 
                     |weight|
                         weighting scheme for choosing strategies
                
                     |strategies| 
                        original strategies that can be suspended
                     
                     |efficiency| 
                         function estimating is the strategy efficient or not
                     
                     |estimator| 
                        function creating phantom strategy used for efficiency estimation
                 
                 """,
    [
        ("strategies", "[FundamentalValue()]", "meta.listOf(ISingleAssetStrategy)"),
        ("weight", "weight.TrackRecord()", "weight.Base"),
        ("efficiency", "efficiencyTrend", "ISingleAssetTrader -> ISingleAssetTrader"),
        ("estimator", "virtualWithUnitVolume", "ISingleAssetStrategy -> ISingleAssetStrategy"),
    ],
    category="Adaptive",
)
    _internals = ['_fundamentalValue']

exec wrapper2("MeanReversion",
             """ Mean reversion strategy believes that asset price should return to its average value.
                 It estimates this average using some functional and 
                 if the current asset price is lower than the average
                 it buys the asset and if the price is higher it sells the asset. 
             
                 It has following parameters: 
                 
                 |orderFactory| 
                     order factory function (default: order.Market.T)
                 
                 |creationIntervalDistr| 
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)
                 
                 |average| 
                     functional used to calculate the average 
                     (default: exponentially weighted moving average with |alpha| = 0.15)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)
             """,
             [('orderFactory',          'order.MarketFactory',              'Side -> Volume -> IOrder'),
              ('average',               'mathutils.ewma(alpha = 0.15)',     'IUpdatableValue'),
              ('volumeDistr',           'mathutils.rnd.expovariate(1.)',    '() -> Volume'),
              ('creationIntervalDistr', 'mathutils.rnd.expovariate(1.)',    '() -> TimeInterval')])

Exemple #14
0
from marketsim import meta, types, registry

from _basic import Strategy
from _wrap import wrapper2
from _lp_side import LiquidityProviderSide

class _Array_Impl(Strategy):
    
    def dispose(self):
        for s in self.strategies:
            s.dispose()

    def suspend(self, flag):
        Strategy.suspend(self, flag)
        for s in self.strategies:
            s.suspend(flag)

    @property
    def suspended(self):
        for s in self.strategies:
            assert s.suspended == self._suspended
        return Strategy.suspended(self)
    
exec wrapper2('Array', "", [('strategies', '[LiquidityProviderSide()]', 'meta.listOf(types.ISingleAssetStrategy)')])
exec wrapper2(
    "TwoAverages",
    """ Two averages strategy compares two averages of price of the same asset but
                 with different parameters ('slow' and 'fast' averages) and when 
                 the first is greater than the second one it buys, 
                 when the first is lower than the second one it sells
                 
                 It has following parameters:

                 |average1| 
                      functional used to obtain the first average
                      (defaut: expenentially weighted moving average with |alpha| = 0.15)
                      
                 |average2| 
                      functional used to obtain the second average
                      (defaut: expenentially weighted moving average with |alpha| = 0.015)
                      
                 |orderFactory| 
                     order factory function (default: order.Market.T)
                     
                 |threshold| 
                     threshold when the trader starts to act (default: 0.)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)

                 |creationIntervalDistr| 
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)                     
             """,
    [
        ("average1", "mathutils.ewma(alpha = 0.15)", "IUpdatableValue"),
        ("average2", "mathutils.ewma(alpha = 0.015)", "IUpdatableValue"),
        ("threshold", "0.", "non_negative"),
        ("orderFactory", "order.MarketFactory", "Side -> Volume -> IOrder"),
        ("creationIntervalDistr", "mathutils.rnd.expovariate(1.)", "() -> TimeInterval"),
        ("volumeDistr", "mathutils.rnd.expovariate(1.)", "() -> Volume"),
    ],
)
                    self._elements[idx] = self._elements[-1]
                # it converges since every time we pops an element from the queue
                self._elements.pop()
            else:
                # if order is valid, cancel it
                self._book.process(order.Cancel(e))
                return

    def __init__(self):

        # orders created by trader
        self._elements = []
        self.wakeUp = bind.Method(self, "_wakeUp_impl")
        self._eventGen = scheduler.Timer(self.cancellationIntervalDistr)
        self._myTrader = trader.SingleProxy()
        self._book = orderbook.OfTrader(self._myTrader)

    _internals = ["_myTrader"]

    def bind(self, ctx):
        event.subscribe(self._myTrader.on_order_sent, bind.Method(self, "process"), self, ctx)
        event.subscribe(self._eventGen, self.wakeUp, self, ctx)

    def process(self, order):
        """ Puts 'order' to future cancellation list
        """
        self._elements.append(order)


exec wrapper2("Canceller", "", [("cancellationIntervalDistr", "mathutils.rnd.expovariate(1.)", "() -> TimeInterval")])
exec wrapper2("LiquidityProviderSide",
             """ Liquidity provider for one side has followng parameters:

                 |side|
                     side of orders to create (default: Side.Sell)
                     
                 |orderFactory| 
                     order factory function (default: order.Limit.T)
                     
                 |initialValue| 
                     initial price which is taken if orderBook is empty (default: 100)
                     
                 |creationIntervalDistr|
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)
                     
                 |priceDistr|
                     defines multipliers for current asset price when price of
                     order to create is calculated (default: log normal distribution with 
                     |mu| = 0 and |sigma| = 0.1)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)

                 It wakes up in moments of time given by *creationIntervalDistr*, checks
                 the last best price of orders in the corresponding queue, takes *initialValue*
                 if it is empty, multiplies it by a value taken from *priceDistr* to obtain price
                 of the order to create, calculates order volume using *volumeDistr*, creates
                 an order via *orderFactoryT(side)* and tells the trader to send it.
             """,
             [('side',                  'Side.Sell',                            'Side'),
              ('orderFactoryT',         'order.LimitFactory',                   'Side -> (Price, Volume) -> IOrder'),
              ('defaultValue',          '100',                                  'Price'),
              ('creationIntervalDistr', 'mathutils.rnd.expovariate(1.)',        '() -> TimeInterval'),
              ('priceDistr',            'mathutils.rnd.lognormvariate(0., .1)', '() -> float'),
              ('volumeDistr',           'mathutils.rnd.expovariate(1.)',        '() -> Volume')])
Exemple #18
0
    @property
    def _signalFunc(self): 
        return self.signal
    
exec wrapper2("Signal", 
             """ Signal strategy listens to some discrete signal
                 and when the signal becomes more than some threshold the strategy starts to buy. 
                 When the signal gets lower than -threshold the strategy starts to sell. 
                 
                 It has following parameters:

                 |signal| 
                      signal to be listened to (default: RandomWalk)
                      
                 |orderFactory| 
                     order factory function (default: order.Market.T)
                     
                 |threshold| 
                     threshold when the trader starts to act (default: 0.7)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)
             """,
             [('signal',        'signal.RandomWalk()',          'IObservable'),  
              ('threshold',     '0.7',                          'non_negative'),
              ('orderFactory',  'order.MarketFactory',          'Side -> Volume -> IOrder'),
              ('volumeDistr',   'mathutils.rnd.expovariate(1.)','() -> Volume')])

class Condition_Impl(object):
    
    def __init__(self, cond, ifpart, elsepart):
Exemple #19
0
exec wrapper2('TrendFollower', 
             """ Trend follower can be considered as a sort of a signal strategy 
                 where the *signal* is a trend of the asset. 
                 Under trend we understand the first derivative of some moving average of asset prices. 
                 If the derivative is positive, the trader buys; if negative - it sells.
                 Since moving average is a continuously changing signal, we check its
                 derivative at random moments of time given by *creationIntervalDistr*. 
                 
                 It has following parameters:
                
                 |average| 
                     moving average functional. By default, we use exponentially weighted
                     moving average with |alpha| = 0.15.
                     
                 |orderFactory| 
                     order factory function (default: order.Market.T)
                     
                 |threshold| 
                     threshold when the trader starts to act (default: 0.)
                     
                 |creationIntervalDistr|
                     defines intervals of time between order creation
                     (default: exponential distribution with |lambda| = 1)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)
             """,
             [('average',                'mathutils.ewma(alpha = 0.15)',  'IUpdatableValue'),
              ('threshold',              '0.',                            'non_negative'), 
              ('orderFactory',           'order.MarketFactory',           'Side -> Volume -> IOrder'),
              ('creationIntervalDistr',  'mathutils.rnd.expovariate(1.)', '() -> TimeInterval'),
              ('volumeDistr',            'mathutils.rnd.expovariate(1.)', '() -> Volume')])
Exemple #20
0
exec wrapper2('LiquidityProvider',
             """ Liquidity provider is a combination of two LiquidityProviderSide traders 
                 with the same parameters but different trading sides. 
                 
                 It has followng parameters:

                 |orderFactory| 
                     order factory function (default: order.Limit.T)
                     
                 |initialValue| 
                     initial price which is taken if orderBook is empty (default: 100)
                     
                 |creationIntervalDistr|
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)
                     
                 |priceDistr|
                     defines multipliers for current asset price when price of
                     order to create is calculated (default: log normal distribution with 
                     |mu| = 0 and |sigma| = 0.1)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)
            """,  
            [('orderFactoryT',          'order.LimitFactory',                   'Side -> (Price, Volume) -> IOrder'),
             ('defaultValue',           '100',                                  'Price'),
             ('creationIntervalDistr',  'mathutils.rnd.expovariate(1.)',        '() -> TimeInterval'),
             ('priceDistr',             'mathutils.rnd.lognormvariate(0., .1)', '() -> float'),
             ('volumeDistr',            'mathutils.rnd.expovariate(.1)',        '() -> Volume')])
exec wrapper2("TwoAverages", 
             """ Two averages strategy compares two averages of price of the same asset but
                 with different parameters ('slow' and 'fast' averages) and when 
                 the first is greater than the second one it buys, 
                 when the first is lower than the second one it sells
                 
                 It has following parameters:

                 |average1| 
                      functional used to obtain the first average
                      (defaut: expenentially weighted moving average with |alpha| = 0.15)
                      
                 |ewma_alpha1| 
                     parameter |alpha| for the first exponentially weighted moving average
                     (default: 0.15.)
                      
                 |ewma_alpha2| 
                     parameter |alpha| for the second exponentially weighted moving average
                     (default: 0.015.)
                      
                 |threshold| 
                     threshold when the trader starts to act (default: 0.)
                     
                 |volumeDistr| 
                     defines volumes of orders to create 
                     (default: exponential distribution with |lambda| = 1)

                 |creationIntervalDistr| 
                     defines intervals of time between order creation 
                     (default: exponential distribution with |lambda| = 1)                     
             """,
             [('ewma_alpha1',           '0.15',                          'non_negative'),
              ('ewma_alpha2',           '0.015',                         'non_negative'),
              ('threshold',             '0.',                            'non_negative'), 
              ('orderFactory',          'order.MarketFactory',           'Side -> Volume -> IOrder'),
              ('creationIntervalDistr', 'mathutils.rnd.expovariate(1.)', '() -> TimeInterval'),
              ('volumeDistr',           'mathutils.rnd.expovariate(1.)', '() -> Volume')])
        buyOrder = order.LimitFactory(Side.Buy)(quote - 5, self.volume)
        sellOrder = order.LimitFactory(Side.Sell)(quote + 5, self.volume)
        self._send(buyOrder)
        self._send(sellOrder)

exec  wrapper2("MarketData",
             """ A Strategy that allows to drive the asset price based on historical market data
             by creating large volume orders for the given price.

             Every time step of 1 in the simulation corresponds to a 1 day in the market data.

             At each time step the previous Limit Buy/Sell orders are cancelled and new ones
             are created based on the next price of the market data.

             |ticker|
                Ticker of the asset

             |start|
                Start date in DD-MM-YYYY format

             |end|
                End date in DD-MM-YYYY format

             |volume|
                Volume of Buy/Sell orders. Should be large compared to the volumes of other traders.
             """,
              [ ('ticker', '"^GSPC"',  'str'),
                ('start', '"2001-1-1"', 'str'),
                ('end', '"2010-1-1"', 'str'),
                  ('volume', '1000', 'Volume')], register=False)