Template

A mostly blank Algo template that can be used as a jump-start for developing a new Algo.

This sample is part of CQG Custom Algo SDK examples included in the algo_centos8_sdk container.
#include "spark/lib/config/config.h"
#include "spark/lib/config/protos/system.pb.h"
#include "spark/lib/domain_model/Security.h"
#include "spark/lib/orderman/orders/algo/IAlgoOrder.h"
#include "spark/lib/orderman/orders/algo/IAlgoServices.h"
#include "spark/lib/plugin/SparkServices.h"

#include "spark/lib/orderman/order_factory/IOrderFactory.h"
#include "spark/lib/orderman/orderman_utils/Book.h"
#include "spark/lib/orderman/orderman_utils/orderman_utils.h"
#include "spark/lib/utils/PBUtils.h"

using namespace bts::api::orderman;
using namespace bts::orderman;

namespace bts {
namespace order_example {

// MyAlgo is a blank IAlgoOrder which you can copy when starting a new Algo
class MyAlgo : public IAlgoOrder {
 public:
   MyAlgo();
   ~MyAlgo();

   OrderOpResult do_before_launch(IBeforeLaunchAlgoServices &) override;
   void do_launch(IAlgoServices &) override;
   void do_launch_attached(IAlgoServices &, OrderKey, ChildState) override;
   void do_update(api::orderman::Update const &) override;
   void on_book(SecurityKey, Book const &) override;
   void on_child_change(OrderKey, ChildState const &) override;

 private:
   IAlgoServices* algo_services;
   ChildTemplate *child_template = nullptr;
   OrderKey child_key = null_order_key();
};


MyAlgo::MyAlgo() : algo_services(nullptr) {}
MyAlgo::~MyAlgo() {}

// This is called outside of the latency sensitive path. 
// Expensive initialization should be done here, rather than in do_launch()
OrderOpResult MyAlgo::do_before_launch(IBeforeLaunchAlgoServices &serv) {
   LOG(Sdk,Info, "MyAlgo: do_before_launch");
   // If we are not attaching, create a child template so we can
   // quickly launch our child when the time comes.
   if (!serv.is_attaching()) {
      // We will be sending a limit order with the same side,
      // security, trader, account, etc, as this algo order, so just
      // copy our definition to the child definition to start with.
      auto child_def = serv.definition();
      // Now add a limit order component to mark our child as a limit
      // order. Limit orders do not require any extra parameters
      // beyond those already inherited from this algo order
      // (i.e. beyond what we obtained through serv.definition()) so
      // we can just use a default constructed LimitOrderDefinition.
      *child_def.mutable_custom_def()->mutable_limit() = LimitOrderDefinition{};
      // Now just build the child template and cache it for future use
      child_template = &(serv.make_child_template(child_def));
   }
   // Default constructed result is successful
   return {};
}

// Called in the latency sensitive path, once, when the algo is first launched. 
// If the Algo is attaching to an existing order do_launch_attached is called instead.
void MyAlgo::do_launch(IAlgoServices &services) {
   algo_services = &services;
   // Subscribe to book updates for this security
   services.subscribe_book(SecurityKey(services.security().id()));
   // Launch a child limit order
   child_key = 
      services.launch_child(*child_template, services.price(), services.quantity());
   LOG(Sdk,Info, "MyAlgo: do_launch");
}

// Called in the latency sensitive path, once, when the algo is first
// launched. In this case the algo is provided with an existing order
// it is now responsible for managing.
void MyAlgo::do_launch_attached(IAlgoServices &services,
                                OrderKey attached_order, ChildState st) {
   algo_services = &services;
   // Subscribe to book updates for this security
   services.subscribe_book(SecurityKey(services.security().id()));
   // Keep track of the child key
   child_key = attached_order;
   LOG(Sdk,Info, "MyAlgo: do_launch_attached");
}

// Called when a human (or a supervising algo) updates a parameter for
// this algo. The implementation validates the update and depending on
// the validation outcome either applies the update or terminates the algo.
void MyAlgo::do_update(api::orderman::Update const &update) {
}

// Called when the book for the specified security has changed
void MyAlgo::on_book(SecurityKey, Book const &b) {
}

// Our child reported a change
void MyAlgo::on_child_change(OrderKey, ChildState const &st) {
}

// This is called by the spark daemon at startup. In this call we
// describe our algo's parameters and register a factory function to
// create an instance of the algo.
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
   using namespace bts;

   DynamicOrderDescriptor desc;

   // Start by naming our order type
   desc.set_dynamic_order_type("My Algo");

   *desc.add_param_desc() = param_bool("Enable Feature");
   *desc.add_param_desc() = param_uint32("Feature Quantity");

   // Associate the descriptor with a builder function and register
   // that with the Spark server.
   auto result = 
      serv.register_dynamic_algo_order(
       desc, []() { return std::make_unique<MyAlgo>(); });

   if (result != bts::AlgoRegistrationResult::SUCCESS) {
      // The desc has errors
      // Check the error log (/sparkdata/data/logging/log) for more details
   }
}

} // namespace order_example
} // namespace bts

  Next