Connecting an agent and its strategy

Discussion in 'C++' started by Claudio Jolowicz, Apr 8, 2004.

  1. I am trying to find a solution to the following design problem
    (code at the bottom):

    We are implementing a trader agent that can trade with other traders
    on an electronical trading platform. To make the trader more
    extensible, we have defined a strategy interface and implemented this
    interface for different trading strategies. The problem relates to how
    to connect the trader and the strategy.

    The problem is tricky because the strategy has to call back the
    trader, for instance to get information about orders (i.e. prices) on
    the trading platform, and to initiate own orders. Technically, the
    strategy constructor takes an argument of type StrategyCallback. The
    latter is an interface which is implemented by the trader class.


    The quick and dirty approach would be the following:

    The user (1) instantiates the trader and then (2) uses the reference
    to the trader to instantiate the strategy. After that (3), the user
    calls a method of the trader that initializes the trader's strategy,
    passing it the reference to the strategy.

    The problem is that the initialization takes place outside of, and
    after the constructor. Also, the user has to worry about internals of
    the trader.


    A bit more elegant is the following approach:

    The strategy cannot be instantiated before the trader. It would be
    nice to let the trader instantiate it. But the trader doesn't know the
    exact type of the strategy. So let's make the trader a template. Like
    this, the initialization can take place in the trader's constructor
    and is hidden from the user.

    We have implemented this approach, and it works. However, it doesn't
    really solve the design problem. Every instantiation of the trader
    template has a different type. The trader class has to be recompiled
    whenever we write a new strategy for it. For the same reason, it is
    awkward to manage a collection of traders with different strategies.


    Is there another way?


    struct Strategy;
    struct StrategyCallback;

    /// trader class aggregating a strategy
    class Trader
    : public StrategyCallback
    {
    public:
    //construction
    Trader(trading::Strategy*);
    ~Trader();
    private:
    Trader(const& Trader);
    Trader& operator=(const Trader&);

    //private data
    Strategy* m_pStrategy;
    };

    /// interface representing a trader's strategy.
    struct Strategy
    {
    virtual ~Strategy() { /*cleanup*/ }

    /// reevaluate situation.
    virtual void evaluate() = 0;

    /// the strategy has reached the goal.
    virtual bool succeeded() = 0;

    /// the strategy has failed.
    virtual bool failed() = 0;

    /// perform the strategy.
    virtual void trade() = 0;
    };

    /// callback interface for strategy.
    struct StrategyCallback
    {
    /// access orders.
    virtual OrderIseq getOrders() = 0;

    /// create an order.
    virtual trading::Order* createOrder(
    double dPrice,
    double dVolume) = 0;
    };

    --
    Claudio Jolowicz

    Department of Computing
    180 Queen's Gate
    South Kensington campus
    Imperial College
    LONDON SW7 2AZ

    31 Humbolt Road
    Fulham
    LONDON W6 8QH

    mobile: +44(0)7963 892810
    mail to:
    webpage: www.doc.ic.ac.uk/~cj603
     
    Claudio Jolowicz, Apr 8, 2004
    #1
    1. Advertising

  2. Claudio Jolowicz

    tom_usenet Guest

    On Thu, 8 Apr 2004 07:15:32 +0100, Claudio Jolowicz
    <> wrote:

    >We are implementing a trader agent that can trade with other traders
    >on an electronical trading platform. To make the trader more
    >extensible, we have defined a strategy interface and implemented this
    >interface for different trading strategies. The problem relates to how
    >to connect the trader and the strategy.
    >
    >The problem is tricky because the strategy has to call back the
    >trader, for instance to get information about orders (i.e. prices) on
    >the trading platform, and to initiate own orders. Technically, the
    >strategy constructor takes an argument of type StrategyCallback. The
    >latter is an interface which is implemented by the trader class.

    [snip]
    >A bit more elegant is the following approach:
    >
    >The strategy cannot be instantiated before the trader. It would be
    >nice to let the trader instantiate it. But the trader doesn't know the
    >exact type of the strategy. So let's make the trader a template. Like
    >this, the initialization can take place in the trader's constructor
    >and is hidden from the user.
    >
    >We have implemented this approach, and it works. However, it doesn't
    >really solve the design problem. Every instantiation of the trader
    >template has a different type. The trader class has to be recompiled
    >whenever we write a new strategy for it. For the same reason, it is
    >awkward to manage a collection of traders with different strategies.
    >
    >Is there another way?


    You could change the Strategy interface to take a StrategyCallback in
    the relevent method calls (such as evaluate and trade). That way there
    is no direct composition relationship between a Strategy and the
    "callback", which might better decouple them (and remove the circular
    reference).

    >struct Strategy;
    >struct StrategyCallback;


    It might be better to call that OrderHandler, or similar, to better
    express its purpose.

    >
    >/// trader class aggregating a strategy
    >class Trader
    > : public StrategyCallback
    >{
    >public:
    > //construction
    > Trader(trading::Strategy*);
    > ~Trader();
    > private:
    > Trader(const& Trader);
    > Trader& operator=(const Trader&);
    >
    > //private data
    > Strategy* m_pStrategy;


    Obviously a smart pointer would be appropriate here (and in the
    constructor).

    Another solution would be to use a StrategyFactory. e.g.

    class StrategyFactory
    {
    public:
    virtual ~StrategyFactory(){};

    typedef shared_ptr<Strategy> StrategyPtr;

    virtual StrategyPtr createStrategy(OrderHandler& handler) = 0;
    };

    template <class Strat>
    class ConcreteStrategyFactory: public StrategyFactory
    {
    public:
    virtual StrategyPtr createStrategy(OrderHandler& handler)
    {
    return StrategyPtr(new Strat(handler));
    }
    };

    and pass that into the Trader constructor (note that the handler must
    outlive the Strategy - avoid circular smart pointer references by
    using a weak_ptr or a reference to the handler as above).

    Tom
    --
    C++ FAQ: http://www.parashift.com/c -faq-lite/
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
     
    tom_usenet, Apr 8, 2004
    #2
    1. Advertising

  3. Claudio Jolowicz wrote:
    >
    > The quick and dirty approach would be the following:
    >
    > The user (1) instantiates the trader and then (2) uses the reference
    > to the trader to instantiate the strategy. After that (3), the user
    > calls a method of the trader that initializes the trader's strategy,
    > passing it the reference to the strategy.
    >
    > The problem is that the initialization takes place outside of, and
    > after the constructor. Also, the user has to worry about internals of
    > the trader.


    Hmm.

    class StrategyCallback
    {
    public:
    virtual OrderIseq getOrders() = 0;
    virtual trading::Order* createOrder( double dPrice, double dVolume) = 0;
    };

    class Strategy
    {
    public:
    Strategy();

    void UseWith( StrategyCallback& TheTrader );
    };

    class Trader : public StrategyCallback
    {
    public:
    Trader( Strategy& UseStrategy ) : m_Strategy( UseStrategy )
    {
    m_Strategy.UseWith( *this );
    };

    protected:
    Strategy m_Strategy;
    };

    int main()
    {
    Strategy MyStrat;
    Trader MyTrader( MyStrat );
    }

    Seems acceptable to me, without having the user of the classes have to know
    to much details about the Trader class. A Trader cannot be instatiated without
    a strategy, thus it cannot be forgotten to give one to it. The passed strategy
    is copied at the moment it is given to the trader thus you can throw away the
    MyStrat in main without affecting the MyTrader (may or may not be what you want).

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, Apr 8, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Apple
    Replies:
    3
    Views:
    306
    Apple
    Aug 1, 2005
  2. thunk
    Replies:
    1
    Views:
    315
    thunk
    Mar 30, 2010
  3. thunk
    Replies:
    0
    Views:
    488
    thunk
    Apr 1, 2010
  4. thunk
    Replies:
    14
    Views:
    626
    thunk
    Apr 3, 2010
  5. Replies:
    0
    Views:
    140
Loading...

Share This Page