Case study · Team project · QuackHacks 2025
Winner, Polymarket Track — QuackHacks 2025Poly Predictor Kit
Understanding markets means understanding both the numbers and the conversation.
A Chrome extension and three local Python services that read a Polymarket event: a Gemini summary of what its prices imply, a classifier's read of whether its comments are emotional or rational, and a check for lopsided risk.
Raimbek's roleDeveloped the market summarization and comment-classification pipelines. Team project: Devpost lists 6 creators.
A Polymarket event
- Prices
- Gamma API
- Prompt
- Gemini
- AI Trade Insight
- Prices
- Gamma API
- Rules
- Steamroller warning
- Comments
- Gamma API
- Classifier
- Emotional or rational share
Project overview
Winner, Polymarket Track — QuackHacks 2025. One Chrome extension reads a market's numbers with Gemini and its conversation with a TF-IDF and logistic-regression classifier. Raimbek developed both of those pipelines; the extension and the risk check are part of the team's architecture.
Explore the system map Raimbek's contributionSource on GitHub
- Raimbek's contribution
- The Gemini-powered market summarization and TF-IDF / logistic-regression comment-classification pipelines.
- Built with
- Python · Flask · Gemini API · Polymarket Gamma API · scikit-learn · Snowflake (Snowpark) · Chrome extension
- Status
- Built in November 2025 at QuackHacks. Runs locally: the extension calls three Flask services on ports 5000–5002. Not deployed.
Raimbek's contribution
The summarizer and the classifier.
Developed the Gemini-powered market summarization and TF-IDF / Logistic Regression comment-classification pipelines as part of the team project that won the Polymarket Track at QuackHacks 2025.
The numbers
Market summarization pipeline
Finds a Polymarket event through the Gamma API, keeps up to three of its markets, reads their prices as probabilities and asks Gemini for a short insight under fixed rules.
Code: poly_event_
The conversation
Comment-classification pipeline
Gemini labels training comments as emotional, rational or spam; TF-IDF features and logistic regression learn those labels; at runtime the saved model reads an event's comments without calling Gemini.
Code: geminiAutoLabelAssigner.py · train_model_snowflake.py · main_api.py
How the classifier worksThe team's architecture
Poly Predictor Kit is a team project. These parts are credited to the team:
- The Chrome extension and its popup, which call all three services.
- The Flask service that wraps the summarizer for the extension.
- The steamroller detector, the risk rule explained under The risk shape.
- A web front page, not connected to the services.
Devpost listsUmar Turdumambetov · Bekzat Uraimov · Shamil Khamrayev · Akan Abdireshov · Zhanbolot Eraliev · Raimbek Alish
Team from Devpost, read on 2026-10-24 Public record
What it does
Three buttons, three readings of one event.
Open any Polymarket event, open the extension, and choose one of three buttons. Each calls its own Python service on the same machine and shows the answer as text.
The numbers
“Poly AI Summarizer”
The event's markets and prices become a structured prompt; Gemini writes a short, hedged summary of what they imply.
What comes back3–6 sentences of plain text: what current prices imply, one or two risks that could change the odds, both sides of the view, and a reminder that it is not financial advice.
Raimbek's pipeline
The conversation
“Emotional Damage Predictor”
Every comment on the event is labeled by a saved scikit-learn model; the result is the share of emotional against rational comments.
Its message, as the code writes itFrom comments provided it seems like the event might be based on Emotions: N%
Raimbek's pipeline
The numbers
“Steamroller Check”
A rule, not a model: flags an outcome whose price leaves a tiny upside and a huge downside.
Its message, as the code writes itSIDE looks like a steamroller trade. Current implied probability is about P%. At this price, one loss wipes roughly N average wins. There are about D days left until resolution.
Team component
Button names and message formats from popup.html and the services Verified in code
System map
Follow an event through the code
Each line is a pipeline in the repository and each station one of its stages. Choose a station to see what it takes, what it does and what it gives, with a link to its code.
- The numbers: prices and volumes
- The conversation: comments
- Stage of Raimbek's pipelines
Market insight
Raimbek's pipelineMarket insight · stage 4 of 6
Structured prompt
- Takes
- The event and its markets.
- Does
- Parses outcome prices, which the Gamma API stores as JSON strings, and writes each as a price and an implied percentage beside its question, status and volume.
- Gives
- A plain-text prompt with the market data and the writing rules.
Comment classifier
Raimbek's pipelineSteamroller check
Team componentRead the system map as text
Market insight (the numbers, “Poly AI Summarizer” button; Raimbek's pipeline)
- Extension button. Reads the event's slug from the tab's address and posts it to the local insight service. Team component.
- Insight service. Passes the slug to the summarizer module and returns its text, or an error. Team component.
- Event and markets. Resolves the event through GET /events/slug/{slug}, /events/{id} or /public-search, then keeps up to three of its markets, open ones first.
- Structured prompt. Parses outcome prices, which the Gamma API stores as JSON strings, and writes each as a price and an implied percentage beside its question, status and volume.
- Gemini. Generates 3–6 sentences on what current prices imply, one or two risks that could move the odds, and both sides of the view. The prompt forbids buy or sell instructions and position sizes, and asks for a not-financial-advice reminder.
- AI Trade Insight. The popup shows it as returned. Team component.
Comment classifier (the conversation, “Emotional Damage Predictor” button; Raimbek's pipeline)
- Extension button. Posts the event's address to the local classifier service. Team component.
- Comments. Pages through GET /comments for the event, 100 at a time, and keeps each comment's text.
- Saved classifier. Loads the trained scikit-learn pipeline from comment_classifier.pkl and predicts one label per comment. No Gemini call happens here.
- Emotional or rational. Counts emotional and rational comments, ignores spam, and reports the larger share.
Steamroller check (the numbers, “Steamroller Check” button; a team component)
- Extension button. Calls the local steamroller service with the event's slug.
- Outcome prices. Fetches the event and takes its first active market's outcomes and prices.
- Risk rules. Per $1: the gain is 1 − p and the loss is p, so one loss erases p ÷ (1 − p) wins. A side is flagged when p is at least 0.9 and that factor at least 10; its score is weighted up when resolution is more than three days away.
- Risk message. Writes the side, its implied probability, how many wins one loss erases, and the days left.
Preparing the classifier (the conversation, before runtime; Raimbek's pipeline)
- Collect comments. Downloads every comment on the event.
- Gemini labels. Asks Gemini 2.5 Flash to label each comment EMOTIONAL, RATIONAL or SPAM from three short definitions, answering in JSON. These labels are training data; Gemini is not used when the extension runs.
- Snowflake table. Appends BODY and LABEL rows to a Snowflake table through Snowpark. Snowflake stores the training data; it does not train the model.
- Train. Splits 80/20 with the labels' proportions kept, fits TfidfVectorizer followed by LogisticRegression, and prints a classification report. No scores are published.
- Model file. Saves it with joblib. The runtime service loads this file. After each analysis that service also appends its own labels to the table and retrains, so later training data includes the model's own labels.
The numbers · Raimbek's part
Prices are read as probabilities before Gemini sees them.
The market summarization pipeline: the module that finds a Polymarket event through the Gamma API, turns its markets into a structured prompt and asks Gemini for a short insight.
Find the event
It accepts what a person would paste: an event's address, its slug, a numeric id or a search phrase. Each goes to the Gamma API through
/events/slug/…,/events/…or/public-search.Keep what matters
Up to three of the event's markets, open ones first, with their questions, status, volume and outcome prices.
Read prices as probabilities
The Gamma API returns outcomes and prices as JSON strings. The module parses them and writes each price beside its implied percentage.
In the API response
outcomes: '["Yes","No"]'outcomePrices: '["0.54","0.46"]'In the prompt
Outcomes: Yes: 0.54 (~54.0%); No: 0.46 (~46.0%)Example values from the module's own docstring; the format is the code's Verified in code Ask with rules
The prompt carries the event's title, status, end date and volume, then each market. It asks Gemini (
gemini-2.5-flash, through the public REST API, with the key read from the environment) for 3–6 sentences under explicit rules:The prompt's instructions and rules, verbatim
poly_event_ai_summarizer.pyVerified in code Using this information, write a short AI Trade Insight section in 3–6 sentences. Focus on: - What current prices roughly imply about market expectations. - 1–2 key scenarios or risk factors that could change the odds. - A balanced view that mentions both upside and downside perspectives. Rules: - Do NOT give explicit instructions like "you should buy" or "sell now". - Do NOT mention specific position sizes. - Explicitly remind the reader that this is NOT financial advice.
The module began as a command-line tool (commit 5f34cdf); the team then wrapped it in the Flask service that the extension calls, with the key loaded from a .env file.
The conversation · Raimbek's part
Gemini labels the training data. A small model reads the comments.
Raimbek developed the comment-classification pipeline. Its two halves run at different times, and only the first uses Gemini.
Before Teaching the classifier
- Collect comments Gamma API · one event
- Gemini labels Training labels only
- Snowflake table COMMENT_LABELS_DATA
- Train scikit-learn, locally
- Model file comment_classifier.pkl
comment_
When the button is pressed Reading the comments
- Comments Gamma API · /comments
- Saved classifier TF-IDF + logistic regression
- Emotional or rational A share, spam left out
The three labels Verified in code
Gemini labels comments with these definitions, verbatim from its prompt. The trained model learns the same three classes.
- EMOTIONAL
- emotion-heavy, opinions, little/no reasoning.
- RATIONAL
- uses reasoning, facts, or structure to support claims.
- SPAM
- off-topic, self-promo, nonsense, low-effort, "gm", etc.
The model
A scikit-learn pipeline: TF-IDF features from the comment text, then logistic regression. It trains on an 80/20 split that keeps the labels' proportions and prints a classification report. No scores are published, so none are claimed here.
The training pipeline, verbatim
model = Pipeline([
("tfidf", TfidfVectorizer()),
("clf", LogisticRegression(max_iter=1000)),
])
Snowflake stores; scikit-learn trains. The labeled comments are appended to a Snowflake table through Snowpark and read back into pandas, and the model is fitted locally. The README's “Snowpark ML training” is not what the code does.
After each analysis, the runtime service appends its own labels to that table and retrains, so later training data includes the model's own labels, not only Gemini's.
The numbers · team component
A rule, not a model: how much one loss can erase.
The third button flags a “steamroller”: an outcome priced so high that winning pays little and losing costs nearly everything. It is arithmetic on the price, and part of the team's architecture.
An explanation, not a trading tool. The calculator below evaluates the team's rule for a price you choose. It uses no market data and recommends nothing.
Price, read as probability93%
- Win per share
- 7¢
- Lose per share
- 93¢
- One loss erases
- 13 wins
The detector would flag this: at least 90%, and at least 10 wins erased by one loss.
Computed in your browser from the team's detector formula, with no market data. It explains the rule; it is not advice. The detector also uses the days left to resolution to grade the risk; that part is not shown here.
Checked against the code
What the code shows, and what it does not.
README: “Snowflake (Snowpark ML training)” and “continuous retraining through Snowflake”.
Snowpark writes and reads the table of labeled comments; the model is trained locally with scikit-learn. The retraining runs inside each analysis request, on the classifier's own labels.
Devpost: the steamroller check “uses liquidity”.
The code uses implied probability, the wipeout factor and days to resolution. Liquidity is not read.
README: an example verdict, “The event looks 67% Emotional.”
An example of the message format. No classifier results or accuracy figures are published, and none are shown here.
A web front page (index.html) with three feature cards.
Its API addresses are placeholders, so it is not wired to the services. The working interface is the extension's popup.
Not claimed Not claimed
- Model accuracy. The training script prints a report, but no scores are published.
- Trading results, recommendations or advice. Nothing on this page trades or recommends; the summary's own prompt rules out buy or sell instructions.
- A deployment. The services run locally on ports 5000–5002.
- Running or sharing the trained classifier. This page explains it; it does not run it.
The team recorded a demo of the working extension: watch it on YouTube
Evidence
How this page knows what it says
What each evidence label means
- Verified in code
- Read in the public repository at commit 475fcd9: its Python services, extension and README.
- Public record
- From the project's Devpost page and the repository's commit history, read on 2026-10-24.
- Conceptual illustration
- Drawn to explain the architecture in the code. Not the extension's interface and not market data.
- Computed in your browser
- The steamroller detector's own formula, evaluated here for a probability you choose. No market data and no model.
- Not claimed
- Stated in the README or on Devpost but not supported by the code, or simply not measured.
What was not used
The trained classifier was not run, loaded or copied, and no market data, prices or comments appear on this page. The Devpost gallery holds only the team's logo, so there are no product screenshots here.