OnixS C++ FIX Engine 2.79.1.0
Scheduling Sessions for Automatic Connection

Modules

 Session Schedule
 Session Connection Settings
 Predefined Schedules and Connection Settings

Detailed Description

In real life Sessions FIX Connections occur at regular intervals. A lot of trading systems have public schedules which declare time frames for trading. Session class exposes members for FIX Connections basic handling. It also provides users with automatic reconnection facility in case of connection failure. However, there is no way in Session functionality to maintain Connections on systematic basis.

Sessions Scheduler

To satisfy the needs of real life trading schedules, the OnixS FIX Engine offers the Sessions Scheduler. This service will automatically connect certain FIX sessions to the counterparty at the beginning of the trading day as well as disconnect at the end of a day. It also possible to keep a FIX Session connected for an entire trading week and disconnect it at the end of last trading day.

The Sessions Scheduler is available as a part of the OnixS FIX Engine.

SessionScheduler class

OnixS::FIX::Scheduling::SessionScheduler is a workhorse class of the Sessions Scheduling services. This class exposes a simple but comprehensive API to handle connections by schedules of any complexity.

Registering a Session for Automatic Connection

OnixS::FIX::Scheduling::SessionScheduler::add member schedules a session for automatic logon and logout according to the specified session time which can be delivered to the Scheduler as an instance of appropriate class or as a name of predefined preset. The parameter of type OnixS::FIX::Scheduling::SessionConnectionSettings specifies the role of Session (either Acceptor or Initiator) and primary connection parameters like host and port which the Session will use to establish the FIX Connection.

Note:
If a Session is being registered at the time noted by schedule, the the scheduler will connect the Session immediately.

Removing a Session from Scheduling Services

OnixS::FIX::Scheduling::SessionScheduler::remove removes given session from the scheduling services.

Note:
OnixS::FIX::Scheduling::SessionScheduler::remove doesn't disconnect active session from trading system. Therefore, if session was already connected by scheduler, it remains connected after unregistering.

Important Behavioral Aspects

The following steps take place while scheduling a Session:

Handling Scheduling Warnings and Errors

Scheduler exposes OnixS::FIX::Scheduling::SessionSchedulerListener class to get notified listeners about errors in session scheduling. OnixS::FIX::Scheduling::SessionSchedulerListener::onError is not linked with session errors. Scheduler raises notifications only about scheduling-related errors like inability to connect session within specified amount of time.

Note:
Once OnixS::FIX::Scheduling::SessionSchedulerListener::onError is called by the scheduler all attempts to logon disconnected session will be suspended till next activity (logon) time.

OnixS::FIX::Scheduling::SessionSchedulerListener::onWarning member is called by the Scheduler to provide its users with more information about scheduling flow. This kind of information usually related with non-critical errors which occur while scheduling a session.

Note:
In case of failure at logon, scheduler will call OnixS::FIX::Scheduling::SessionSchedulerListener::onWarning member and will try to perform logon again according to the settings from the Engine configuration (Reconnect.Attempts and Reconnect.Interval values). Once all attempts are performed and session remains disconnected, Scheduler will invoke OnixS::FIX::Scheduling::SessionSchedulerListener::onError member and will stop all subsequent attempts to bring a session to connected state untill next logon time.

Example

class SchedulingIssueDetector 
    : public SessionSchedulerListener
{
public:
    SchedulingIssueDetector()
    {
    }

    ~SchedulingIssueDetector()
    {
    }

    virtual void onLoggingOut(
        const SessionScheduler& scheduler,
        Session* session,
        bool* allowLogout)
    {
        // Nothing to do.
    }

    virtual void onWarning(
        const SessionScheduler& scheduler, 
        Session* session, 
        const std::string& warningReason)
    {
        cout 
            << "Scheduler reported a warning for the session "
            << static_cast<const string&>(*session)
            << ": "
            << warningReason;
    }

    virtual void onError(
        const SessionScheduler& scheduler, 
        Session* session, 
        const std::string& errorReason)
    {
        cout 
            << "Error occurred while scheduling session "
            << static_cast<const string&>(*session)
            << ": "
            << errorReason;
    }
};

class Sample
{
public:
    Sample()
    {
        initializeFixEngine();
        
        constructSessions();
        
        constructScheduler();
    }

    ~Sample()
    {
        initiator_->shutdown();
        initiator_.reset();

        acceptor_->shutdown();
        acceptor_.reset();

        scheduler_.reset();

        Engine::shutdown();             
    }

    void run()
    {
        acceptor_->reset();
        initiator_->reset();

        acceptor_->logonAsAcceptor();

        cout 
            << "Scheduling session "
            << static_cast<const string&>(*initiator_)
            << " for automatic connection."
            << endl;

        SessionSchedule initiatorSchedule = 
            constructShortTimeActivitySchedule();

        InitiatorConnectionSettings 
        initiatorConnectivity("localhost", sessionPort());

        scheduler_->add(
            initiator_.get(),
            initiatorSchedule,
            initiatorConnectivity);

        cout 
            << "Waiting for activity on scheduled session "
            << static_cast<const string&>(*initiator_)
            << "."
            << endl
            << endl;

        // Should sleep for a while to let scheduler 
        // connect session until wait for disconnecting.
        OnixS::Threading::ThisThread::sleep(
            1000 * sessionActivityTimeInSeconds());

        waitUntilLogout(initiator_.get());

        cout 
            << endl
            << "Removing session "
            << static_cast<const string&>(*initiator_)
            << " from scheduling service."
            << endl;

        // Session had to 'pulse' connection till this 
        // time, so scheduling can be shutted down.
        scheduler_->remove(initiator_.get());

        // Clean-up.
        acceptor_->logout();
        waitUntilLogout(acceptor_.get());

        // End of game.
        cout << endl << "Done." << endl;
    }

private:
    auto_ptr<Session> acceptor_;
    ISessionListener acceptorListener_;

    auto_ptr<Session> initiator_;
    SessionStateChangeTracer initiatorStateChangeTracer_;

    auto_ptr<SessionScheduler> scheduler_;
    SchedulingIssueDetector schedulingIssueDetector_;

    void constructScheduler()
    {
        SessionSchedulerOptions schedulerOptions;
        schedulerOptions.eventListener(&schedulingIssueDetector_);

        scheduler_.reset(new SessionScheduler(schedulerOptions));
    }

    void constructSessions()
    {
        acceptor_.reset(
            new Session(
                acceptorCompId(), 
                initiatorCompId(), 
                protocolVersion(), 
                &acceptorListener_));

        initiator_.reset(
            new Session(
                initiatorCompId(), 
                acceptorCompId(), 
                protocolVersion(), 
                &initiatorStateChangeTracer_));
    }

    static
    SessionSchedule 
    constructShortTimeActivitySchedule()
    {
        TimeOfDay now = TimeOfDay::now();

        TimeOfDay logonTime = 
            now + TimeSpan::Seconds(5);

        TimeOfDay logoutTime = 
            logonTime + 
            TimeSpan::Seconds(
            sessionActivityTimeInSeconds());

        return SessionSchedule(
            DaysOfWeek::Monday, 
            DaysOfWeek::Sunday, 
            logonTime, 
            logoutTime, 
            SessionDurations::Day, 
            SequenceNumberResetPolicies::Never);
    }

    static void waitUntilLogout(Session* session)
    {
        const unsigned oneSecondPause = 1000;

        while (session->getState() != Session::DISCONNECTED)
            OnixS::Threading::ThisThread::sleep(oneSecondPause);
    }

    static void initializeFixEngine()
    {
        EngineSettings settings;
            
        settings.listenPort(sessionPort());

        Engine::init(settings);
    }

    static string initiatorCompId()
    {
        return "Initiator";
    }

    static string acceptorCompId()
    {
        return "Acceptor";
    }

    static Version protocolVersion()
    {
        return FIXForge::FIX::FIX_42;
    }

    static int sessionPort()
    {
        return 4500;
    }

    static int sessionActivityTimeInSeconds()
    {
        return 30;
    }
};