![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
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