RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
examples/bidding_agent_ex.cc
00001 
00009 #include "rtbkit/common/bids.h"
00010 #include "rtbkit/core/banker/slave_banker.h"
00011 #include "rtbkit/core/agent_configuration/agent_config.h"
00012 #include "rtbkit/plugins/bidding_agent/bidding_agent.h"
00013 #include "soa/service/service_utils.h"
00014 
00015 #include <boost/program_options/cmdline.hpp>
00016 #include <boost/program_options/options_description.hpp>
00017 #include <boost/program_options/positional_options.hpp>
00018 #include <boost/program_options/parsers.hpp>
00019 #include <boost/program_options/variables_map.hpp>
00020 
00021 #include <iostream>
00022 #include <thread>
00023 #include <chrono>
00024 
00025 using namespace std;
00026 using namespace ML;
00027 
00028 namespace RTBKIT {
00029 
00030 /******************************************************************************/
00031 /* FIXED PRICE BIDDING AGENT                                                  */
00032 /******************************************************************************/
00033 
00039 struct FixedPriceBiddingAgent :
00040         public BiddingAgent
00041 {
00042     FixedPriceBiddingAgent(
00043             std::shared_ptr<Datacratic::ServiceProxies> services,
00044             const string& serviceName) :
00045         BiddingAgent(services, serviceName),
00046         accountSetup(false)
00047     {}
00048 
00049 
00050     void init()
00051     {
00052         // We only want to specify a subset of the callbacks so turn the
00053         // annoying safety belt off.
00054         strictMode(false);
00055 
00056         onBidRequest = bind(
00057                 &FixedPriceBiddingAgent::bid, this, _1, _2, _3, _4, _5, _6);
00058 
00059         // This component is used to speak with the master banker and pace the
00060         // rate at which we spend our budget.
00061         budgetController.init(getServices()->config);
00062         budgetController.start();
00063 
00064         // Update our pacer every 10 seconds. Note that since this interacts
00065         // with the budgetController which is only synced up with the router
00066         // every few seconds, the wait period shouldn't be set too low.
00067         addPeriodic("FixedPriceBiddingAgent::pace", 10.0,
00068                 [&] (uint64_t) { this->pace(); });
00069 
00070         BiddingAgent::init();
00071     }
00072 
00073     void start()
00074     {
00075         BiddingAgent::start();
00076 
00077         // Build our configuration and tell the world about it.
00078         setConfig();
00079     }
00080 
00081     void shutdown()
00082     {
00083         BiddingAgent::shutdown();
00084 
00085         budgetController.shutdown();
00086     }
00087 
00088 
00090     void setConfig()
00091     {
00092         config = AgentConfig();
00093 
00094         // Accounts are used to control the allocation of spending budgets for
00095         // an agent. The whole mechanism is fully generic and can be setup in
00096         // whatever you feel it bests suits you.
00097         config.account = {"hello", "world"};
00098 
00099         // Specify the properties of the creatives we are trying to show.
00100         config.creatives.push_back(Creative::sampleLB);
00101         config.creatives.push_back(Creative::sampleWS);
00102         config.creatives.push_back(Creative::sampleBB);
00103 
00104         // Set our frequency cap to 42. This has two effects: 1) it instructs
00105         // the router that we want bid requests destined for our agent to first
00106         // be augmented with frequency capping information and 2) it instructs
00107         // the frequency cap augmentor to tag any bid requests for which we've
00108         // seen the user less the 42 times.
00109         config.addAugmentation("frequency-cap-ex", Json::Value(42));
00110 
00111         // Instructs the router to only keep bid requests that have this tag. In
00112         // other words keep only the bid requests that our agents has seen less
00113         // then 42 times.
00114         config.augmentationFilter.include.push_back("pass-frequency-cap-ex");
00115 
00116 
00117         // Tell the world about our config. We can change the configuration of
00118         // an agent at any time by calling this function.
00119         doConfig(config);
00120     }
00121 
00122 
00126     void bid(
00127             double timestamp,
00128             const Id & id,
00129             std::shared_ptr<RTBKIT::BidRequest> br,
00130             Bids bids,
00131             double timeLeftMs,
00132             const Json::Value & augmentations)
00133     {
00134         for (Bid& bid : bids) {
00135 
00136             // In our example, all our creatives are of the different sizes so
00137             // there should only ever be one biddable creative. Note that that
00138             // the router won't ask for bids on imp that don't have any
00139             // biddable creatives.
00140             ExcAssertEqual(bid.availableCreatives.size(), 1);
00141             int availableCreative = bid.availableCreatives.front();
00142 
00143             // We don't really need it here but this is how you can get the
00144             // AdSpot and Creative object from the indexes.
00145             (void) br->imp[bid.spotIndex];
00146             (void) config.creatives[availableCreative];
00147 
00148             // Create a 2$ CPM bid with our available creative. Note that by
00149             // default, the bid price is set to 0 which indicates that we don't
00150             // wish to bid on the given spot.
00151             bid.bid(availableCreative, USD_CPM(2));
00152         }
00153 
00154         // A value that will be passed back to us when we receive the result of
00155         // our bid.
00156         Json::Value metadata = 42;
00157 
00158         // Send our bid back to the agent.
00159         doBid(id, bids, metadata);
00160     }
00161 
00162 
00164     void pace()
00165     {
00166         // We need to register our account once with the banker service.
00167         if (!accountSetup) {
00168             accountSetup = true;
00169             budgetController.addAccountSync(config.account);
00170         }
00171 
00172         // Make sure we have 1$ to spend for the next period.
00173         budgetController.topupTransferSync(config.account, USD(1));
00174     }
00175 
00176 
00177     AgentConfig config;
00178 
00179     bool accountSetup;
00180     SlaveBudgetController budgetController;
00181 };
00182 
00183 } // namepsace RTBKIT
00184 
00185 
00186 /******************************************************************************/
00187 /* MAIN                                                                       */
00188 /******************************************************************************/
00189 
00190 int main(int argc, char** argv)
00191 {
00192     using namespace boost::program_options;
00193 
00194     Datacratic::ServiceProxyArguments args;
00195 
00196     options_description options = args.makeProgramOptions();
00197     options.add_options() ("help,h", "Print this message");
00198 
00199     variables_map vm;
00200     store(command_line_parser(argc, argv).options(options).run(), vm);
00201     notify(vm);
00202 
00203     if (vm.count("help")) {
00204         cerr << options << endl;
00205         return 1;
00206     }
00207 
00208     auto serviceProxies = args.makeServiceProxies();
00209     RTBKIT::FixedPriceBiddingAgent agent(serviceProxies, "fixed-price-agent-ex");
00210     agent.init();
00211     agent.start();
00212 
00213     while (true) this_thread::sleep_for(chrono::seconds(10));
00214 
00215     // Won't ever reach this point but this is how you shutdown an agent.
00216     agent.shutdown();
00217 
00218     return 0;
00219 }
00220 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator