Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Botbet #2

Merged
merged 25 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ edition = "2021"

[dependencies]
log = "0.4.20"
queues = "1.1.0"
env_logger = "0.10.1"
serde_json = "1.0.108"
async-trait = "0.1.74"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0.193", features = ["derive"] }
reqwest = { version = "0.11.22", features=["blocking", "json"] }
async-trait = "0.1.74"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Some* of the trading structure has been put toogether in terrible rust code.

[0] https://manifold.markets/browse?topic=extreme-probabilities-project
[1] https://manifold.markets/1941159478/will-republicans-win-pennsylvania-g
[2] https://manifold.markets/firstuserhere/who-will-win-the-chess-champions-to#OuFcRSwEts5SEGoHk1wj
156 changes: 102 additions & 54 deletions src/bots.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
use std::collections::HashMap;

use async_trait::async_trait;
use log::{debug, info, warn};
use tokio::sync::broadcast::Receiver;
use log::{debug, error, info, warn};
use tokio::sync::{broadcast, mpsc};

use crate::manifold_types;
use crate::market_handler;

#[async_trait]
pub trait Bot {
async fn run(&mut self, rx: Receiver<manifold_types::Bet>);
async fn run(&mut self, rx: broadcast::Receiver<manifold_types::Bet>);
fn get_id(&self) -> String;
fn close(&self);
fn botbet_to_posty_packet(&self, bet: manifold_types::BotBet) -> market_handler::PostyPacket;
}

pub struct ArbitrageBot {
id: String,
market: manifold_types::FullMarket,
answers: HashMap<String, manifold_types::Answer>,
bot_to_mh_tx: mpsc::Sender<market_handler::PostyPacket>,
mh_to_bot_rx: broadcast::Receiver<market_handler::PostyPacket>,
}

impl ArbitrageBot {
pub fn new(market: manifold_types::FullMarket) -> Self {
pub fn new(
id: String,
market: manifold_types::FullMarket,
bot_to_mh_tx: mpsc::Sender<market_handler::PostyPacket>,
mh_to_bot_rx: broadcast::Receiver<market_handler::PostyPacket>,
) -> Self {
let mut id_to_answers = HashMap::new();

match &market.answers {
Some(answers) => {
for answer in answers {
id_to_answers.insert(answer.id.clone(), answer.clone());
}
}
None => {
warn!("market {} has no answers", &market.lite_market.question);
error!("market {} has no answers", &market.lite_market.question);
panic!("market {} has no answers", &market.lite_market.question);
}
}

Self {
id,
market,
answers: id_to_answers,
bot_to_mh_tx,
mh_to_bot_rx,
}
}

Expand All @@ -46,29 +61,44 @@ impl ArbitrageBot {
tot_prob
}

fn bet_amount(&self) -> f64 {
let mut bet_map: HashMap<String, manifold_types::BotBet> = HashMap::new();
fn bet_amount(&self) -> Vec<manifold_types::BotBet> {
let mut bets: Vec<manifold_types::BotBet> = vec![];
let inverse_sum: f64 = self.answers.values().map(|a| 1.0 / a.probability).sum();

for answer in self.answers.values() {
let bb = manifold_types::BotBet {
bets.push(manifold_types::BotBet {
amount: 100. * (1. / answer.probability) / inverse_sum,
contract_id: self.market.lite_market.id.clone(),
outcome: manifold_types::MarketOutcome::Other(answer.id.clone()),
};
bet_map.insert(answer.id.clone(), bb);
};
info!("BET MAP{:?}", bet_map);
outcome: manifold_types::MarketOutcome::Yes,
answer_id: Some(answer.id.clone()),
});
}

assert!((bet_map.values().map(|bb| bb.amount).sum::<f64>() - 100.).abs() < 1e-5, "sum of bets {} != 100", bet_map.values().map(|bb| bb.amount).sum::<f64>());
bets
}

async fn make_bets(&mut self, bets: Vec<manifold_types::BotBet>) {
for bet in bets {
self.bot_to_mh_tx
.send(self.botbet_to_posty_packet(bet))
.await
.unwrap();

0.
match self.mh_to_bot_rx.recv().await {
Ok(resp) => {
info!("made bet {:?}", resp);
}
Err(e) => {
error!("mh_to_bot_rx gave error {e}");
}
}
}
}
}

#[async_trait]
impl Bot for ArbitrageBot {
async fn run(&mut self, mut rx: Receiver<manifold_types::Bet>) {
async fn run(&mut self, mut rx: broadcast::Receiver<manifold_types::Bet>) {
info!("starting arbitrage bot");

let tot_prob = self.find_arb();
Expand All @@ -77,54 +107,72 @@ impl Bot for ArbitrageBot {
} else {
info!("NOT ARB OPPORTUNITY {tot_prob}");
}
self.bet_amount();

let bets_to_make = self.bet_amount();

info!("want to make {} bets", bets_to_make.len());
debug!("bets to make {:?}", bets_to_make);

self.make_bets(bets_to_make).await;

let mut i: u64 = 0;
loop {
match rx.recv().await {
Ok(bet) => {
debug!("{i} {:?}", bet);

let answer_id = &bet.answer_id.expect("answer_id is None");

debug!(
"answer_id {answer_id} prob before {} new prob {} our previous prob{}",
&bet.prob_before,
&bet.prob_after,
self.answers.get_mut(answer_id).unwrap().probability
);

let bet_prev_prob = &bet.prob_before;
let bet_after_prob = &bet.prob_after;
let our_prev_prob = &self.answers.get_mut(answer_id).unwrap().probability;

if bet_prev_prob != our_prev_prob {
warn!(
"bet_prev_prob {} != our_prev_prob {}",
bet_prev_prob, our_prev_prob
);
}

self.answers.get_mut(answer_id).unwrap().probability = *bet_after_prob;

let tot_prob = self.find_arb();
if tot_prob >= 1. {
info!("FOUND ARB OPPORTUNITY! {tot_prob}");
} else {
info!("NOT ARB OPPORTUNITY {tot_prob}");
}

self.bet_amount();

i += 1;
}
let bet: manifold_types::Bet = match rx.recv().await {
Ok(bet) => bet,
Err(e) => {
warn!("in ArbitrageBot::run {e}");
continue;
}
};

debug!("{i} {:?}", bet);

let answer_id = &bet.answer_id.expect("answer_id is None");

debug!(
"answer_id {answer_id} prob before {} new prob {} our previous prob{}",
&bet.prob_before,
&bet.prob_after,
self.answers.get_mut(answer_id).unwrap().probability
);

let bet_prev_prob = &bet.prob_before;
let bet_after_prob = &bet.prob_after;
let our_prev_prob = &self.answers.get_mut(answer_id).unwrap().probability;

if bet_prev_prob != our_prev_prob {
warn!(
"bet_prev_prob {} != our_prev_prob {}",
bet_prev_prob, our_prev_prob
);
}

self.answers.get_mut(answer_id).unwrap().probability = *bet_after_prob;

i += 1;
}
}

fn botbet_to_posty_packet(&self, bet: manifold_types::BotBet) -> market_handler::PostyPacket {
market_handler::PostyPacket::new(
self.get_id(),
market_handler::Method::Post,
"bet".to_string(),
vec![],
Some(serde_json::json!({
"amount": bet.amount,
"contractId": bet.contract_id,
"outcome": bet.outcome,
"answerId": bet.answer_id
})),
None,
)
}

fn get_id(&self) -> String {
self.id.clone()
}

fn close(&self) {
println!("closing arbitrage bot");
}
Expand Down
5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ mod bots;
mod errors;
mod manifold_types;
mod market_handler;
mod rate_limiter;
mod utils;

#[tokio::main]
async fn main() {
Expand Down Expand Up @@ -39,7 +41,8 @@ async fn main() {
serde_json::to_string_pretty(&arb_market).unwrap()
);

let mut bot = ArbitrageBot::new(me.clone(), arb_market.clone());
let (bot_to_mh_tx, rx_bot) = market_handler.posty_init("bawt".to_string()).await.unwrap();
let mut bot = ArbitrageBot::new("bawt".to_string(), arb_market.clone(), bot_to_mh_tx, rx_bot);

let rx = market_handler
.get_bet_stream_for_market_id(arb_market.lite_market.id)
Expand Down
Loading