Skip to content

Commit

Permalink
Updating Profilepage, Positions, Capability to Sell Shares (openpredi…
Browse files Browse the repository at this point in the history
…ctionmarkets#61)

* Updating selling logic, math libraries so that we can implement selling.

* Fixed placebet.go.

* Updating, attempting to implement selling and position calculations, README.md thinking.

* Update with github compatible math.

* Update, adding .md

* Adding tick marks math to attempt to display properly.

* Update, attempting to render formula with skipped lines.

* Attempt to use align to keep each line aligned properly.

* Attempt to use f alignment.

* Sepearte equation from definitions.

* Attempting to add math tag to math blocks.

* Adding horizontal rule.

* Tweaking title and horz rule.

* Update, adding S calcuations.

* Update.

* Attempting to fix formula.

* Update.

* Fixing align.

* Fixing align.

* Fixing falign.

* Update dividing up market pool shares.

* Updating introducing course payout.

* Updating.

* Updating, attempting to format correctly.

* Debugging _ in math mode error.

* Removing $ from R - p

* Attempging to realign equations.

* Further formatting.

* Update.

* Update.

* Update formatting and top paragraph.

* Update.

* Update.

* Update.

* Update, clarifiying.

* Update.

* Update again, correcting.

* Attempting to fix again.

* Fixing equivalency, introduce D variable.

* Hopefully final cleanup.

* Reorganization, adding functions for dbpm

* Reorganization, adding functions for dbpm

* Theoretically complete market positions handler.

* Fixing bugs in dbpm calculation.

* Updating conventions, changing bets to integers.

* Converting all currency stuff to int64

* Converting all currency stuff to int64

* Update again, just cleaning up integers.

* Update, ironing out ints problem.

* Finished refactoring to use int64 as base currency, however market position calculations not working, slice not lined up

* Updated market payout information, however final payout still not calculating properly.

* Fixing low shares problem.

* Updating, working adjusted market positions.

* Updating readme.

* Further updates, including the capability to sell shares as a function of buying.

* Updating, attempting to play around with debugging math for selling positions.

* Update, improving buying with liquidating shares, proper logic.

* Update profile, attempting to fix bet sell shres rule.

* Attempting to fix problems again.

* setup Vite instead of CRA

* Update placebethandler, marketpositionshandler, dbpm_marketshares to calculate positions as an aggregate net.

* Update sellpositionhandler.

* Draft: Creating branch to update node such that vite will work. (openpredictionmarkets#62)

* Creating branch to update node such that vite will work.

* Noop modification to frontend.Dockerfile to allow packages to install properly. You have to make a modification to the Dockerfile above where the step you're trying to update is in order for Docker to pick up that part of the file.

* fix: changed the file extension to match Vite 5.x version

* Attempting to fix ports so works with nginx.

* Got it working. needed to add --host flag after vite command on package.json.

* Fixing networking, ensuring that frontend serves on a static network within docker so that we can allow it within CORS configuration. Upgrading to Node 21.

* Update, making compose-dev universal

---------

Co-authored-by: Marko Kovač <[email protected]>

* Frontend/folder restructure (openpredictionmarkets#65)

* complete folder restructure of the project

* rest of the folder setup

* complete folder restructure of the project

* rest of the folder setup

* fix for isLoggedIn default state

* Profilepage sellshares (openpredictionmarkets#66)

* Update capability to sell position handler, still working on it.

* Update, fixing import cycles.

* Moving MarketDetails to pages/ rather than components/ (openpredictionmarkets#73)

* Blk system dependencies upgrade (openpredictionmarkets#75)

* Update having added to dependencies: blk-design-system-react: github:creativetimofficial/blk-design-system-react#1.2.2,

* implemented the theme, added needed dependencies for it

* Adding reactstrap to package.json and package-lock.json.

---------

Co-authored-by: Marko Kovač <[email protected]>

* Revert "Blk system dependencies upgrade (openpredictionmarkets#75)"

This reverts commit 9f98611.

* Tailwind setup

* Stylepage to Hold Individual Elements (openpredictionmarkets#102)

* Adding test button to start style page.

* Adding bet no and bet yes buttons to style page.

* Attempting to centralize colors and refactor to simplify repeatable elements of buttons.

* Update.

* Converting colors.jsx to tailwind.config.js

* Converting colors.jsx to tailwind.config.js

* Updated to use tailwind as central place for colors and styles.

* Removing Colors.jsx as central styling location, migrating everything to tailwind.config.js

* Adding resolve button.

* Update further.

* Stripping off App.css to attempt to use nothing but tailwind and build up from there.

* Updating with tweaks to sidebar, color, etc.

* Various styling updates.

* Updating various styling, breaking down MarketDetails.

* Adding sitebuttons, inputbar, loginmodal, index, etc.

* Reorganizing to make new marketdetails styling work.

* Updating fees.

* Working line chart with d3.js

* Updating, area step chart with d3js.

* Responsive graph, expands with window expansion.

* Working zoomable area fill step chart.

* Update, ensuring that canvasjs is installed.

* Updating button colors to abide by color scheme from colors.co

* Updating Markets.jsx, throwing out old.

* Fully deleting Markets.jsx old page and css.

* Updating Create.jsx with new button and form.

* Fix API_URL error. However still have Error reading request body

* Updating, attempting to fix login.

* Allow login modal to show up on center of DOM via adding modal div within index.html and changing how login modal rendered.

* Moving toward getting login flow working.

* Noop test change.

* Succesful login with new method.

* Attempting to pull routes out of App.jsx to clean up further.

* Update frontend routing, ensuring styling fits together.

* Login/logout working, showing expanded sidebar.

* Got full login working again.

* Got create functionality to the point where now date is picking up as end of today, but user not being passed.

* Update.

* Update InputBar and InputBox such that they can both accept input and have no default value.

* Updating footer copyright date to 2024.

* Adding check for update on login state within Auth to keep user logged in when checking endpoints.

* Starting to update marketdetails page.

* Updating.

* Fixing charts and tables so test data populates through.

* Updating to make workable.

* Rearranging marketdetails layout, including calculation of current proabbility.

* Simplifying authorization as it relates to secure actions.

* Slight tweaks to simplify login process.

* Redirect to same page after login.

* Updating.

* Added modal draft.

* Update, resolve modal working.

* Adding isResolved logic.

* Adding placebet modal button.

* Tweaking, updating bet buttons.

* Updating bet modal and buttons.

* Fixing loginmodal.

* No longer working, messing with hooks to try to make marketdetails reload upon successful bet.

* Updating page working.

* Updating chart with currentProbability, starting ActivityModal.

* Setting up activity tabs, hack for login and reloading of isLoggedIn.

* Bet layout grid working.

* Attempting to update positions display.

* Showing positions.

* Update, adding trading tabs.

* Working tabs for betting modal.

* Adding coin in bets activity.

* Update API to include /v0/markets/positions/{marketId}/{username}

* Adding sell shares capability to modal.

* Updating sell buttons, navbar, sidebar.

* Updating column headers.

* Update, populating market table with actual market details from each market.

* Adding functionality to be able to toggle between full and partial description display.

* Adding validation on sell and buy side.

* Updating state so that market chart updates with trades.

* Update.

* Fix sell button so that maximum sell can't be more than shares owned.

* Update, adding tests to fix divide by zero calculations problem.

* Fix kill market with back and fourth trades.

* Fix testing, restrict title and description length.

* Updating with public profile information.

* Update frontend stuff, profile things.

---------

Co-authored-by: Marko Kovač <[email protected]>
  • Loading branch information
pwdel and markokovac16 authored May 17, 2024
1 parent eeda619 commit fa56339
Show file tree
Hide file tree
Showing 168 changed files with 13,609 additions and 24,746 deletions.
22 changes: 22 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
BACKEND_IMAGE_NAME=socialpredict-backend-dev
BACKEND_CONTAINER_NAME=socialpredict-backend-container-dev
BACKEND_PORT=8080 # Internal
BACKEND_HOSTPORT=8086 # External

POSTGRES_CONTAINER_NAME=db-postgres-dev
DB_HOST=db
DB_PORT=5433 # port accessible on host machine
POSTGRES_PORT=5432 # port where postgres serves by default in container"$DB_PORT:$POSTGRES_PORT"
POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_DATABASE=devdb

FRONTEND_IMAGE_NAME=socialpredict-frontend-dev
FRONTEND_CONTAINER_NAME=socialpredict-frontend-dev
REACT_PORT=5173 # Internal
REACT_HOSTPORT=5173 # External

NGINX_IMAGE_NAME=socialpredict-nginx-dev
NGINX_CONTAINER_NAME=socialpredict-nginx-dev
NGINX_PORT=80 # Internal
NGINX_HOSTPORT=8089 # External
4 changes: 2 additions & 2 deletions .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ POSTGRES_DATABASE=devdb

FRONTEND_IMAGE_NAME=socialpredict-frontend-dev
FRONTEND_CONTAINER_NAME=socialpredict-frontend-dev
REACT_PORT=3000 # Internal
REACT_HOSTPORT=3000 # External
REACT_PORT=5173 # Internal
REACT_HOSTPORT=5173 # External

NGINX_IMAGE_NAME=socialpredict-nginx-dev
NGINX_CONTAINER_NAME=socialpredict-nginx-dev
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ SocialPredict's mission is to provide a versatile platform that:
* [Info on Market Mathematics](/README/README-MATH.md)
* [Info on How Economics Can Be Customized](/README/README-CONFIG.md)
* [Info on Development Conventions](/README/README-CONVENTIONS.md)
* [Info on Feature Roadmap](/README/README-ROADMAP.md)
* [Info on Feature Roadmap](/README/README-ROADMAP.md)

.
35 changes: 34 additions & 1 deletion README/README-CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,23 @@

The following is a documentation of various coding conventions used to keep SocialPredict clean, maintainable and secure.

## Seperation of Concerns

* The application is separated into a backend and a frontend so that people who specialize in different areas can easily contribute seperately.
* The backend is written in Golang to do the processing of data, transactions, hold models and so fourth. We use Golang because it is a highly performant language with a wide adoption rate. [In some scenarios, with the proper optimizations, Golang in terms of raw processing power can beat equivalent Rust code](https://www.reddit.com/r/golang/comments/16q78g2/re_golang_code_3x_faster_than_rust_equivalent/). (Though factoring in I/O this might not be the case).
* The frontend is built with ReactJS, similarly because as a platform it has a high adoption rate.

## Backend

### Ab Initio

* The entire program should be as stateless as possible, bets should be ideally made in one ledger and all reporting from that point on are calculated in a stateless manner.
* User balances may be cached, though in an ideal world user balance should also be calculated ab initio, and compared to the cached amount for verification.

### Points Start with Integers

* All transactions must start as integer amounts rather than float amounts. There are mathematical conventions which later transparently account for drops in points throughout market mechanisms.

### Specific Data Structs for Private and Public Responses

* For certain sensitive databases such as Users, there is Private information and Public information. When information from the Users table is needed to be combined with other types of tables such as Bets or Markets, we must be sure to use a function which specifically only returns public information that we explicitly allow, to prevent private information or even private fields from leaking through into API responses.
Expand Down Expand Up @@ -86,4 +100,23 @@ func GetPublicUserInfo(db *gorm.DB, username string) PublicUserType {
### Time-Based Validations Occur on Server Side, Not Client Side

* While logic could be built on the client side that governs the display of buttons, we don't validate time-based actions based upon client time.
* Hypothetically a user could manipulate their browser time to be running in the past, so we don't rely on browsers to tell us what time it is for the purposes of rulemaking. If a user wants to fiddle with the interface and show themselves action that won't be taken, we don't care, but they can't take an action on the API.
* Hypothetically a user could manipulate their browser time to be running in the past, so we don't rely on browsers to tell us what time it is for the purposes of rulemaking. If a user wants to fiddle with the interface and show themselves action that won't be taken, we don't care, but they can't take an action on the API.

### Definition of Handlers

* From the standpoint of both golang packages and the actual function names, "handlers," means something specific, e.g. something responds to an HTTP request. Following the conventon of the Golang http/net package, it specifically means [responds to an HTTP request](https://pkg.go.dev/net/http#Handler).
* So don't just call any old function a handler, make sure it has something to do with an http request, it is likely a hierarchically top level function that draws down from the API, e.g. it is the first function that is called when someone hits `api/v0/whatever`.

#### Handler Response Types

* Ideally, every handler should have its own type which pre-designates what is included in the response.

### Database Connection Pooling

* We should use database connection pooling, e.g. starting likely mostly from a handler, we should set up a database connection such as:

```
db := util.GetDB()
```

* Then moving down from there, we should try to pass db into subsequent functions so that each query being done is using the same connection, rather than running `db := util.GetDB()` again and again within each subsequent function.
226 changes: 226 additions & 0 deletions README/README-MATH-PROB-AND-PAYOUT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
### Market Probability Adjustment and Outcome Update Mechanisms

Two phases of [Double Auctions](https://en.wikipedia.org/wiki/Double_auction) occuring over time arguably exist:

1. The time from the start of the auction to just before the end of the auction, where buyers and sellers are mutually determining a price at any given time during the auction.
2. The end price of the market, which determines how all participants get paid out.

To that end, we have established two mathematical frameworks which allow buying and selling of shares in a binary market to allow (1) which updates the market probability (or possibly better stated, the [normalized price, between 0 and 1](https://forum.effectivealtruism.org/posts/cJc3f4HmFqCZsgGJe/don-t-interpret-prediction-market-prices-as-probabilities)), and a fair payout mechanism which incentivizes risk taking and divergent opinions.

* (1) Formula for Updating Market Probability - Weighted Probability Adjustment Model (WPAM)
* (2) Market Outcome Update Formulae - Divergence-Based Payout Model (DBPM)

#### Formula for Updating Market Probability - Weighted Probability Adjustment Model (WPAM)

* The Weighted Probability Adjustment Model is our base model and the math functions for this can be viewed by searching our codebase for WPAM. WPAM is designed to update the probability of an outcome based on the total amount bet on each possibility. It gives more weight to the initial settings (initial probability and investment) to stabilize the market in its early phase.

---
##### WPAM Formula for Updating Market Probability

```math
\begin{align*}
P_{\text{new}} &= \frac{P_{\text{initial}} \times I_{\text{initial}} + A_{\text{YES}}}{I_{\text{initial}} + A_{\text{YES}} + A_{\text{NO}}} \\
\end{align*}
```

```math
\begin{flalign*}
& \text{where:} & \\
& P_{\text{new}} \text{ is the new probability.} & \\
& P_{\text{initial}} \text{ is the initial probability, set to 0.5.} & \\
& I_{\text{initial}} \text{ is the initial investment, assumed to be 10 points.} & \\
& A_{\text{YES}} \text{ is the total amount bet on "YES".} & \\
& A_{\text{NO}} \text{ is the total amount bet on "NO".} &
\end{flalign*}
```
---

* Initial Probability as a Weighted Factor: The initial probability (P_initial) is typically set to represent a balanced or neutral starting point for the market, often 0.5 for a 50-50 chance. This value is used as a weighted factor in the numerator to establish the baseline influence on the market's direction.
* The cost of creating the market is a way of weighting the market as an initial investment (I_initial). While the (P_initial) is meant to represent blind uncertainty, a 50-50 chance of any market created, the (I_initial) is meant to represent a form of stability, which is why it is included in both the numerator and denominator. If there is a larger initial investment, such that (I_initial) >> (A_YES) or (A_NO) this implies that the market will not move as much until larger (A_YES) or (A_NO) is invested.

#### Example Orders and Outcomes

1. (I_initial) of 10, (P_initial) of 0.50, (A_NO) order made in amount of 20.

```math
P_{\text{new}} = \frac{0.5 \times 10}{10 + 0 + 20} = \frac{5}{30} \approx 0.167
```

2. Same as above but (A_YES) order made in amount of 10.

```math
P_{\text{new}} = \frac{0.5 \times 10 + 10}{10 + 10 + 0} = \frac{15}{20} = 0.75
```

3. Follow up order on (2) made in (A_NO) direction.

```math
P_{\text{new}} = \frac{0.5 \times 10}{10 + 0 + 20} = \frac{5}{30} \approx 0.167
```

#### Market Outcome Update Formulae - Divergence-Based Payout Model (DBPM)

Once a market has been resolved, there is a series of steps that need to be carried out in order to fairly pay out all of the participants based upon how they had bet throughout the duration of the market.

One method of paying out all of the participants might be to simply proportionally cut up the winning pool(s) into shares that are proportional to the amount bet by every participant. However, this doesn't reward those who identified inefficiencies in the market because it doesn't offer much incentive to bet on markets that are either high probability or low probability.

So instead, we need to come up with an operation where every user's bet will be rewarded in proportion to how far it was to the final probability. The following is an explination of the steps we use to calculate the payouts using DBPM.

##### Step One - Dividing Total Payout Pool into YES and NO Payout Pools

* Markets should hypothetically be able to resolve at any given probability. That being said, a complete, "YES" resolution could be defined as resolving at 1 while a complete, "NO" resolution could be defined as 0. Anything in between those numbers could be defined as R.
* If we accept the total pool of bets into the market from the start, meaning the sum of all bet amounts as the total betting tool, then we could calculate the share of that pool, S for either the YES or NO direction.

---
##### DBPM Formula for Dividing Up Market Pool Shares

```math
\begin{flalign*}
& \text{Given:} & \\
& R \in \mathbb{R}, 0 < R < 1 : \text{Resolution probability (ranging from 0 to 1)} & \\
& S \in \mathbb{Z}^+ : \text{Total share pool, sum of all bet amounts} & \\
\end{flalign*}
```

```math
\begin{align*}
& S_{\text{YES}} = \left\lfloor S \cdot R \right\rceil & \\
\end{align*}
```

```math
\begin{align*}
& S_{\text{NO}} = \left\lfloor S \cdot (1 - R) \right\rceil & \\
\end{align*}
```

```math
\begin{flalign*}
& \text{Note that the end result pools S' are produced using Banker's Rounding.} & \\
\end{flalign*}
```

* [Banker's Rounding, Wikipedia](https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even)

---

* It's important to note that the inputs, b_i should be integers, while the probabilities, p_i should be floats. If the p_i is not a float, then there needs to be some kind of ultimate normalized resolution, e.g. between 0 and 100 or 0 and 1000 which represents a probability level p_i or R. So given this, the above calculation will result in fractional shares of S.
* There should ideally be a convention showing what to do with these fractional shares, optionally distribute and always favor one side, randomly favor a side, or create a residual pool which some how gets distributed to users in some manner or acts as a, "tax" on users, perhaps preventing inflation.

##### Step Two - Individual Payout Calculation

* Understanding that we have a series of bets with individual amounts in both YES and NO direction, but we want to incentivize bets that are further away from the R to reward predictors:
* We can introduce d_i, the Reward Factor, representing the linear deviation of the bet's probability p from the resolution probability, R.
* This may be multiplied by the bet amount b_i for any given bet to give us an individual course payout C.

##### DBPM Formula for Calculating Reward Factor

---

```math
\begin{flalign*}
& \text{For Each Bet } i: & \\
\end{flalign*}
```

```math
\begin{align*}
& d_i = |R - p_i| \quad & \\
& C_i = d_i \times b_i & \\
\end{align*}
```

```math
\begin{flalign*}
& \text{where:} & \\
& R : \text{Resolution probability (ranging from 0 to 1)} & \\
& b_i : \text{Bet amount of bet } i & \\
& p_i : \text{Market probability at the time of bet } i & \\
& d_i : \text{the Reward Factor, representing the linear deviation from the R to p at b} & \\
& C_i : \text{he Course payout prior to normalization} & \\
\end{flalign*}
```

---

##### Step Three - Scaling Course Payout to Actual Amount of Capital Pool Available

* The above Step Two may have introduced a problem, where calculating every individual share of every individual better may have either undershot or overshot the amount of capital available in the captial pool (e.g. the actual cash or points available that everyone has thrown into the auction).


```math
\begin{flalign*}
& \text{Step 1: Calculate Course Payouts} & \\
\end{flalign*}
```

```math
\begin{align*}
& C_i \text{ (Course Payout) } = d_i \times b_i & \\
& \text{where } d_i = |R - p_i| & \\
\end{align*}
```

```math
\begin{flalign*}
& \text{Step 2: Sum Course Payouts, C for Each Pool} & \\
\end{flalign*}
```

```math
\begin{align*}
& C_{\text{YES}} = \sum_{i \in \text{YES}} C_i & \\
& C_{\text{NO}} = \sum_{i \in \text{NO}} C_i & \\
\end{align*}
```

```math
\begin{flalign*}
& \text{Step 3: Calculate Normalization Factor, F for Each Pool} & \\
\end{flalign*}
```

```math
\begin{align*}
& F{\text{ (Normalization Factor)}_{\text{YES}}} = \min\left(1, \frac{S_{\text{YES}}}{\text{C}_{\text{YES}}}\right) & \\
& F{\text{ (Normalization Factor)}_{\text{NO}}} = \min\left(1, \frac{S_{\text{NO}}}{\text{C}_{\text{NO}}}\right) & \\
\end{align*}
```

* The above Step 3 does the following:

###### When C>S:

* Use the original normalization to scale down payouts, ensuring that total payouts do not exceed S.

###### When C<S:

* Since scaling payouts with a very small divisor could distort the risk-reward balance that participants agreed upon by massively expanding a payout pool unintentionally, any adjustment to increase C towards S should be done with clear rules and transparency about how these adjustments are made and under what conditions. Therefore our arbitrary rule is to only allow the S/C ratio to ever have a minimum of 1, so we don't get into a scenario where a huge payout due to a small divisor is created unintentionally. Unfortunately this means that actual points can get dropped in the final payout, but this is done to prevent undeserved balooning of payouts.


```math
\begin{flalign*}
& \text{Step 4: Apply Normalization to Calculate Final Payouts} & \\
\end{flalign*}
```

```math
\begin{align*}
& \text{Final Payout}_i = \text{C}_{\text{YES or NO}} \times \text{F}_{\text{YES or NO}} & \\
\end{align*}
```

##### Step Four

```math
\begin{flalign*}
& {Total Payout Distribution, D} & \\
\end{flalign*}
```

```math
\begin{align*}
& D_YES = \sum{\text{Payout}_i \text{ for all YES bets to distribute } S_{\text{YES}}} & \\
& D_NO = \sum{\text{Payout}_i \text{ for all NO bets to distribute } S_{\text{NO}}} & \\
\end{align*}
```
Loading

0 comments on commit fa56339

Please sign in to comment.