Skip to content
Open
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
7 changes: 7 additions & 0 deletions public/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,13 @@
"tooltip": "Minimum profit to consider for trading",
"link": "https://quantframe.app/features/live-trading/settings/item/wts#min-profit"
},
"min_profit_percentage": {
"label": "Minimum Profit Percentage (%)",
"placeholder": "Minimum Profit Percentage",
"error": "Invalid minimum profit percentage",
"tooltip": "Minimum profit as a percentage of the purchase price. Both this and Minimum Profit are enforced. Set to -1 to disable.",
"link": "https://quantframe.app/features/live-trading/settings/item/wts#min-profit-percentage"
},
"max_price_drop": {
"label": "Max Price Drop",
"placeholder": "Max Price Drop",
Expand Down
5 changes: 3 additions & 2 deletions src-tauri/src/app/types/settings/item_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct ItemSettings {
impl ItemSettings {
pub fn get_query_id(&self) -> String {
format!(
"volume_threshold:{};profit_threshold:{};avg_price_cap:{};trading_tax_cap:{};max_total_price_cap:{};price_shift_threshold:{};buy_quantity:{};min_wtb_profit_margin:{};min_sma:{};min_profit:{}",
"volume_threshold:{};profit_threshold:{};avg_price_cap:{};trading_tax_cap:{};max_total_price_cap:{};price_shift_threshold:{};buy_quantity:{};min_wtb_profit_margin:{};min_sma:{};min_profit:{};min_profit_percentage:{}",
self.wtb.volume_threshold,
self.wtb.profit_threshold,
self.wtb.avg_price_cap,
Expand All @@ -20,7 +20,8 @@ impl ItemSettings {
self.wtb.buy_quantity,
self.wtb.min_wtb_profit_margin,
self.wts.min_sma,
self.wts.min_profit
self.wts.min_profit,
self.wts.min_profit_percentage
)
}
}
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/app/types/settings/item_wts_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
pub struct ItemWtsSettings {
pub min_sma: i64,
pub min_profit: i64,
pub min_profit_percentage: i64,
pub max_price_drop: i64,
pub min_listings_below: i64,
}
Expand All @@ -13,6 +14,7 @@ impl Default for ItemWtsSettings {
Self {
min_sma: 3,
min_profit: 10,
min_profit_percentage: -1,
max_price_drop: -1,
min_listings_below: -1,
}
Expand Down
31 changes: 29 additions & 2 deletions src-tauri/src/live_scraper/modules/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ use crate::{
static COMPONENT: &str = "LiveScraper:Item:";
static LOG_FILE: &str = "live_scraper_item.log";

fn minimum_profit_threshold(bought_price: i64, flat_profit: i64, percentage: i64) -> i64 {
if is_disabled(percentage) {
flat_profit
} else {
flat_profit.max(bought_price.saturating_mul(percentage).saturating_add(99) / 100)
}
}

#[derive(Debug)]
pub struct ItemModule {
client: Weak<LiveScraperState>,
Expand Down Expand Up @@ -745,9 +753,14 @@ impl ItemModule {
stock_item.locked = true;
}

// Ensure profit meets the minimum threshold by raising the price if needed
// Ensure profit meets the flat or percentage threshold by raising the price if needed
let mut profit = post_price - bought_price;
let minimum_profit = min_profit.unwrap_or(settings.wts.min_profit);
let flat_minimum_profit = min_profit.unwrap_or(settings.wts.min_profit);
let minimum_profit = minimum_profit_threshold(
bought_price,
flat_minimum_profit,
settings.wts.min_profit_percentage,
);

if !is_disabled(minimum_profit) && profit < minimum_profit {
let adjustment = minimum_profit - profit;
Expand Down Expand Up @@ -1128,3 +1141,17 @@ impl ItemModule {
fn comp(suffix: &str) -> String {
return format!("{}{}", COMPONENT, suffix);
}

#[cfg(test)]
mod tests {
use super::minimum_profit_threshold;

#[test]
fn combines_flat_and_percentage_profit_thresholds() {
assert_eq!(minimum_profit_threshold(20, -1, 25), 5);
assert_eq!(minimum_profit_threshold(200, -1, 25), 50);
assert_eq!(minimum_profit_threshold(1, -1, 1), 1);
assert_eq!(minimum_profit_threshold(20, 10, 25), 10);
assert_eq!(minimum_profit_threshold(20, 10, -1), 10);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ export const WTSItemAccordion = ({ form }: WTSItemAccordionProps) => {
radius="md"
{...form.getInputProps(getFieldPath("min_profit"))}
/>
<NumberInput
label={useTranslateFormFields("min_profit_percentage.label")}
min={-1}
max={999}
placeholder={useTranslateFormFields("min_profit_percentage.placeholder")}
rightSection={<TooltipIcon label={useTranslateFormFields("min_profit_percentage.tooltip")} link={useTranslateFormFields("min_profit_percentage.link")} />}
radius="md"
{...form.getInputProps(getFieldPath("min_profit_percentage"))}
/>
<NumberInput
label={useTranslateFormFields("min_sma.label")}
min={-1}
Expand Down
1 change: 1 addition & 0 deletions src/types/tauri.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export namespace TauriTypes {
min_listings_below: number;
}
export interface ItemWtsSettings {
min_profit_percentage: number;
volume_threshold: number;
profit_threshold: number;
avg_price_cap: number;
Expand Down
Loading