+++
title = "Template"
weight = 5
+++
A mostly blank Algo template that can be used as a jump-start for developing a new Algo.
```cpp
#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(); });
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
```