Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .env.dev
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
POSTGRES_USER=finwar
POSTGRES_PASSWORD=password
POSTGRES_DB=finwar
DATABASE_URL=postgresql://finwar:password@localhost:5432/finwar
FINWAR_MARKET_DATABASE_URL=postgresql://finwar:password@localhost:5432/finwar
RUST_LOG=info
5 changes: 3 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ services:
context: ./servers/rust-server
dockerfile: docker/Dockerfile
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-finwar}:${POSTGRES_PASSWORD:-password}@timescaledb:5432/${POSTGRES_DB:-finwar}
FINWAR_MARKET_DATABASE_URL: postgresql://${POSTGRES_USER:-finwar}:${POSTGRES_PASSWORD:-password}@timescaledb:5432/${POSTGRES_DB:-finwar}
RUST_LOG: info
command: migrate
depends_on:
Expand All @@ -40,7 +40,8 @@ services:
ports:
- "4444:4444"
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-finwar}:${POSTGRES_PASSWORD:-password}@timescaledb:5432/${POSTGRES_DB:-finwar}
FINWAR_MARKET_DATABASE_URL: postgresql://${POSTGRES_USER:-finwar}:${POSTGRES_PASSWORD:-password}@timescaledb:5432/${POSTGRES_DB:-finwar}
FINWAR_MARKET_TARGET_TICKER: NVDA
RUST_LOG: info
command: serve
depends_on:
Expand Down
2 changes: 1 addition & 1 deletion servers/rust-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "finwar-market"
version = "0.2.0"
version = "0.4.0"
authors = ["Coding Kelps <contact@kelps.org>"]
autotests = true
categories = ["finance", "simulation"]
Expand Down
10 changes: 10 additions & 0 deletions servers/rust-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,13 @@ or in powershell:
```powershell
Invoke-RestMethod -Uri http://localhost:4444/api/enroll -Method POST -ContentType "application/json" -Body '{"name":"bot0"}'
```

## Configuration

| Name | Description | Default |
| :------------------------------------ | :-------------------------------------------------------------------- | :---------------------: |
| FINWAR_MARKET_ADDR | The HTTP server address. | `0.0.0.0` |
| FINWAR_MARKET_PORT | The HTTP server port | `4444` |
| FINWAR_MARKET_INTERVAL_SECONDS | The internal time passed (in seconds) in the Market each real second. | `60` |
| FINWAR_MARKET_TARGET_SYMBOL | The target stock symbol on which the Market simulation is based on. | `AAPL` |
| FINWAR_MARKET_DATABASE_URL | The URL with authentication information of the backend database. | |
6 changes: 4 additions & 2 deletions servers/rust-server/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ pub async fn run() -> Result<(), crate::error::Error> {
match opts.command {
Command::Serve => {
let database_url =
std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
std::env::var("FINWAR_MARKET_DATABASE_URL")
.expect("FINWAR_MARKET_DATABASE_URL must be set");

let db_connection = sea_orm::Database::connect(&database_url)
.await
Expand All @@ -34,7 +35,8 @@ pub async fn run() -> Result<(), crate::error::Error> {
},
Command::Migrate => {
let database_url =
std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
std::env::var("FINWAR_MARKET_DATABASE_URL")
.expect("FINWAR_MARKET_DATABASE_URL must be set");

let db_connection = sea_orm::Database::connect(&database_url)
.await
Expand Down
4 changes: 2 additions & 2 deletions servers/rust-server/src/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl MarketClock {
}

pub fn advance(&mut self, seconds: u64) {
self.current_time = self.current_time + Duration::from_secs(seconds * 60);
self.current_time = self.current_time + Duration::from_secs(seconds);
}
}

Expand All @@ -50,4 +50,4 @@ pub async fn time(State(state): State<AppState>) -> Result<impl IntoResponse, Ap
let clock = state.clock.read().await;
let time_str = clock.current_time().format("%Y-%m-%d %H:%M:%S").to_string();
Ok(time_str)
}
}
2 changes: 1 addition & 1 deletion servers/rust-server/src/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn calculate_ma(period: usize, data: &[Vec<f64>]) -> Vec<f64> {

pub async fn chart(state: &AppState) -> Result<Chart, AppError> {
let records = stocks_history::Entity::find()
.filter(stocks_history::Column::Symbol.eq("AAPL"))
.filter(stocks_history::Column::Symbol.eq(&state.target_symbol))
.order_by_asc(stocks_history::Column::Time)
.limit(300)
.all(&state.db)
Expand Down
31 changes: 18 additions & 13 deletions servers/rust-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,11 @@ pub mod trade;

use axum::{Router, response::Redirect, routing::get, routing::post};
use dotenvy::dotenv;
use sea_orm::DatabaseConnection;
use sea_orm::EntityTrait;
use sea_orm::QueryOrder;
use sea_orm::{DatabaseConnection, EntityTrait, QueryOrder, QueryFilter, ColumnTrait};
use std::sync::Arc;
use tokio::sync::RwLock;
use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer;
use tracing::Level;
use tracing::event;
use tower_http::{services::ServeDir, trace::TraceLayer};
use tracing::{Level, event};

use crate::bot::bot_detail;
use crate::clock::time;
Expand Down Expand Up @@ -49,16 +45,25 @@ async fn main() -> Result<(), Error> {
/// Start the HTTP server. Separated out so `main` can dispatch to either
/// the server or other management subcommands (like `migrate`).
pub async fn run_server(db: DatabaseConnection) -> Result<(), Error> {
let tick_interval_seconds = std::env::var("TICK_INTERVAL_SECONDS")
.unwrap_or_else(|_| "1".to_string())
let addr = std::env::var("FINWAR_MARKET_ADDR")
.unwrap_or_else(|_| "0.0.0.0".to_string());

let port = std::env::var("FINWAR_MARKET_PORT")
.unwrap_or_else(|_| "4444".to_string())
.parse::<u64>()
.expect("FINWAR_MARKET_PORT must be a valid integer");

let tick_interval_seconds = std::env::var("FINWAR_MARKET_INTERVAL_SECONDS")
.unwrap_or_else(|_| "60".to_string())
.parse::<u64>()
.expect("TICK_INTERVAL_SECONDS must be a valid integer");
.expect("FINWAR_MARKET_INTERVAL_SECONDS must be a valid integer");

let addr = "0.0.0.0";
let port = 4444;
let target_symbol = std::env::var("FINWAR_MARKET_TARGET_SYMBOL")
.unwrap_or_else(|_| "AAPL".to_string());

let start_time = entity::stocks_history::Entity::find()
.order_by_asc(entity::stocks_history::Column::Time)
.filter(entity::stocks_history::Column::Symbol.eq(&target_symbol))
.one(&db)
.await
.map_err(Error::InitDb)?
Expand All @@ -73,7 +78,7 @@ pub async fn run_server(db: DatabaseConnection) -> Result<(), Error> {
)));
start_clock(Arc::clone(&clock));

let state = AppState::new(db, clock).await.map_err(Error::State)?;
let state = AppState::new(db, clock, target_symbol).await.map_err(Error::State)?;

let app = Router::new()
.route("/", get(|| async { Redirect::to("/home") }))
Expand Down
4 changes: 3 additions & 1 deletion servers/rust-server/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ pub struct AppState {
pub starting_cash: f64,
pub starting_assets: i32,
pub clock: SharedClock,
pub target_symbol: String,
}

impl AppState {
pub async fn new(db: DatabaseConnection, clock: SharedClock) -> Result<Self, StateError> {
pub async fn new(db: DatabaseConnection, clock: SharedClock, target_symbol: String) -> Result<Self, StateError> {
Ok(AppState {
db,
uuid_prefix_length: 18,
starting_cash: 10000.0,
starting_assets: 0,
clock,
target_symbol,
})
}
}
1 change: 1 addition & 0 deletions servers/rust-server/src/trade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ async fn get_current_price(state: &AppState) -> Result<f64, AppError> {
let current_time = state.clock.read().await.current_time();

let stock = stocks_history::Entity::find()
.filter(stocks_history::Column::Symbol.eq(&state.target_symbol))
.filter(stocks_history::Column::Time.lte(current_time))
.order_by_desc(stocks_history::Column::Time)
.one(&state.db)
Expand Down