Skip to main content
A sophisticated stock market system for RedM servers that allows players to buy, sell, and trade stocks with various configuration options. The system supports real-time stock data, random price fluctuations, and RP events that can affect stock prices.
This script provides a complete stock market experience with real-time data integration, dynamic price fluctuations, and immersive RP events that create a living economy for your server.

Features

Real-time Stock Data

Connect to real-world stock data sources for authentic market behavior and price movements.

Randomized Fluctuations

Dynamic price changes with configurable volatility and maximum change percentages for in-game economy.

RP Event System

Create in-game events that affect stock prices, adding depth and immersion to your server’s economy.

Dividend System

Earn passive income from your investments with configurable dividend payouts and intervals.

Admin Controls

Full control over stock behavior, events, and market conditions through comprehensive admin tools.

Player Portfolios

Track investments and performance over time with detailed portfolio management and analytics.

Installation

1

Download

Get the latest release from our Tebex Store and download it from your Keymaster
2

Extract

Extract the script folder to your server’s resources directory
3

Configure

Add ensure spooni_stockmarket to your server.cfg
4

Customize

Configure the script to your liking using the configuration options
5

Restart

Restart your server to activate the stock market system

Configuration

The script is highly configurable through the config/config_stockmarket.lua file. Here are the main configuration sections:

General Settings

config.lua
Config = {}

Config.debug = false

-- General Settings
Config.General = {
    PriceUpdateInterval = 12, --in hours (and every restart automatically)
    EnableRPEvents = true,
    EnableDividends = true,
    DividendInterval = 3, --how long the holder must hold at least one stock of that company to receive dividends (default 3 days)
    DividendPayoutDay = 15, --day in month
    Language = "en", --must be defined in language.lua
}

Administration Settings

config.lua
Config.Administration = {
    isAdmin = function(src)
        return IsPlayerAceAllowed(src, "spooni_stockmarket.admin") --in permissions it would look like "add_ace group.admin spooni_stockmarket.admin allow"
    end,
    --if you want to use a custom function to check if a player is admin, you can set it here
    --example:
    --isAdmin = function(src)
    --    return exports['myframework']:IsAdmin(src)
    --end
    -- or with jobs:
    --isAdmin = function(src)
    --    return Bridge.getJob(src) == "police"
    --end
}
To set up admin permissions, add the following line to your server.cfg:
add_ace group.admin spooni_stockmarket.admin allow

Custom Data Sources

config.lua
-- Custom Influence your Stocks (Only use if you know what you are doing)
Config.CustomDataSources = {
    --[[ ["VCC"] = function()
        local cash = exports.myeconomy:getCompanyBalance("valentine_coal")
        return cash / 1000
    end,

    ["SBF"] = function()
        local reserves = exports.bank_system:getReserves("saint_denis")
        return reserves / 500
    end, ]]
}
Custom data sources should only be used if you understand how they affect stock pricing. Incorrect implementation can lead to unstable market behavior.

Command Configuration

config.lua
Config.Commands = {
    enabled = true, --enable commands (set to false if you dont want players to access it everywhere via command)
    onlyAdmin = true, -- if true, only admins can use the command
    openStockmarketCommand = "stockmarket", --open stockmarket 
}

Location-Based Access

config.lua
--if you want to use locations to open the stockmarket, you can set them here (leave Config.Locations empty if you dont want to use locations)
Config.useLocationNames = false --if you want to use the name of the location as Title of the Stockmarket
Config.PromptKey = 0x760A9C6F --key to open the stockmarket
Config.Locations = {
    SaintDenis = {
        name = "Saint Denis Stockmarket",
        blipsprite = 249721687, --set to false if you dont want a blip
        coords = vector3(2651.8323, -1292.5818, 52.2455),
        distance = 2.0,
        jobs = {"police"}, --if you want to joblock it, set it here otherwise leave empty
    }
}
The prompt key 0x760A9C6F corresponds to the G key. You can change this to any other key code as needed.

Database Setup

The database is created automatically when the resource is started. The system includes the following tables:
  • stocks: Stock definitions and configuration
  • player_portfolios: Player investment tracking
  • transactions: Trade history and audit trail
  • dividends: Dividend payout records
The database structure is automatically managed by the script. No manual database setup is required.

Sample Stocks

Here are 5 sample stocks you can add to your database after starting the script for the first time:
INSERT INTO `stocks` (`id`, `label`, `description`, `base_price`, `volatility`, `type`, `item_name`, `item_enabled`, `realtime_source`, `realtime_symbol`, `realtime_weight`, `random_enabled`, `random_weight`, `random_max_change`, `custom_weight`, `rp_events_enabled`, `dividends_enabled`, `dividends_mode`, `dividends_amount`, `dividends_percent`, `enabled`) VALUES
	('AMCO', 'Annesburg Mining', 'Industrial mining operations', 45, 1, 'mixed', 'stock_amco', 0, NULL, 'NVDA', 1, 1, 1, 3, 0, 1, 1, 'fixed', 2, 0, 1),
	('BWTC', 'Blackwater Trading Co.', 'Merchants and traders since 1878', 85, 1, 'mixed', 'stock_bwtc', 0, NULL, 'AMZN', 1, 1, 1, 3, 0, 1, 1, 'percent', 0, 1, 1),
	('SDBT', 'Saint Denis Bank & Trust', 'Leading financial institution in Lemoyne', 250, 1, 'mixed', 'stock_sdbt', 0, NULL, 'BRK.B', 1, 1, 1, 3, 0, 1, 1, 'percent', 0, 1, 1),
	('STLB', 'Strawberry Lumber', 'Premium timber and wood products', 60, 1, 'mixed', 'stock_stlb', 0, NULL, 'AAPL', 1, 1, 1, 3, 0, 1, 1, 'percent', 0, 1.8, 1),
	('VCC', 'Valentine Coal Co.', 'Mining company based in the Heartlands', 100, 1, 'mixed', 'stock_vcc', 0, NULL, 'TSLA', 1, 1, 1, 3, 0, 1, 1, 'percent', 0, 2.5, 1);

Real-time Stock Symbols

You can choose from over 100 real-world stock symbols. Here are some popular options:
AAPL, MSFT, GOOGL, GOOG, NVDA, META, TSLA, ADBE, CRM, INTC, QCOM, IBM, ORCL, NOW, PANW
BRK.B, JPM, V, MA, BAC, WFC, GS, C, MS, SCHW, AXP, BLK, SPGI, CB, MMC
UNH, JNJ, PFE, LLY, ABBV, MRK, ABT, TMO, DHR, BMY, GILD, MDT, SYK, ISRG, VRTX
AMZN, HD, WMT, MCD, SBUX, TGT, TJX, COST, MCD, DIS, NFLX, NKE, PM, MO
XOM, CVX, COP, NEE, DUK, SO, CAT, LMT, RTX, NOC, HON, DE, UPS, FDX
To request specific stock symbols or get the complete list, please visit our Discord server.

Database Table Structure

The stock market system uses a database table called stocks to store all stock configurations. Each stock is defined by a single row in this table with the following fields:

Stock Table Fields

  • id (string): Unique stock identifier (e.g., “VCC”, “AMCO”)
  • label (string): Display name shown to players (e.g., “Valentine Coal Co.”)
  • description (string): Detailed description of the company/stock
  • base_price (integer): Initial stock price when first created
  • volatility (float): Price volatility multiplier (1.0 = normal, 2.0 = double volatility)
  • enabled (boolean): Whether the stock is active and tradeable
  • type (string): Stock calculation method - “realtime”, “random”, “custom”, or “mixed”
  • realtime_source (string): API provider name for real-time data (e.g., “api_provider”)
  • realtime_symbol (string): Stock symbol for real-time data (e.g., “AAPL”, “TSLA”)
  • realtime_weight (float): Influence of real-time data on price (0.0 to 1.0)
  • random_enabled (boolean): Enable random price fluctuations
  • random_weight (float): Influence of random fluctuations on price (0.0 to 1.0)
  • random_max_change (float): Maximum percentage change per update cycle
  • custom_weight (float): Influence of custom data sources on price (0.0 to 1.0)
  • Currently disabled
  • dividends_enabled (boolean): Enable dividend payouts for this stock
  • dividends_mode (string): “fixed” for set amount or “percent” for percentage
  • dividends_amount (float): Fixed dividend amount (used when mode is “fixed”)
  • dividends_percent (float): Dividend percentage (used when mode is “percent”)
  • rp_events_enabled (boolean): Enable RP events to affect this stock’s price

Stock Type Examples

-- Stock that follows real-world market data
type = "realtime"
realtime_source = "api_provider"
realtime_symbol = "AAPL"
realtime_weight = 1.0
random_enabled = 0
random_weight = 0
custom_weight = 0
-- Stock with purely random price movements
type = "random"
realtime_source = NULL
realtime_symbol = NULL
realtime_weight = 0
random_enabled = 1
random_weight = 1.0
random_max_change = 5.0
custom_weight = 0
-- Stock combining multiple price influences
type = "mixed"
realtime_source = "api_provider"
realtime_symbol = "TSLA"
realtime_weight = 0.6
random_enabled = 1
random_weight = 0.3
random_max_change = 3.0
custom_weight = 0.1
-- Stock influenced by custom data sources
type = "custom"
realtime_source = NULL
realtime_symbol = NULL
realtime_weight = 0
random_enabled = 0
random_weight = 0
custom_weight = 1.0

Database Usage Examples

Creating a Real-time Stock

-- Example: Apple-inspired technology stock
INSERT INTO `stocks` (
    id, label, description, base_price, volatility, type, 
    item_name, item_enabled, realtime_source, realtime_symbol, realtime_weight,
    random_enabled, random_weight, random_max_change, custom_weight,
    rp_events_enabled, dividends_enabled, dividends_mode, dividends_amount, dividends_percent, enabled
) VALUES (
    'TECH', 'Valentine Tech Co.', 'Innovative technology solutions', 
    150, 1.2, 'realtime', 'stock_tech', 1, 
    'api_provider', 'AAPL', 1.0, 
    0, 0, 0, 0, 
    1, 1, 'percent', 0, 2.0, 1
);

Creating a Randomized Stock

-- Example: Local business with random fluctuations
INSERT INTO `stocks` (
    id, label, description, base_price, volatility, type, 
    item_name, item_enabled, realtime_source, realtime_symbol, realtime_weight,
    random_enabled, random_weight, random_max_change, custom_weight,
    rp_events_enabled, dividends_enabled, dividends_mode, dividends_amount, dividends_percent, enabled
) VALUES (
    'LOCAL', 'Local Business', 'Small local enterprise', 
    25, 0.8, 'random', 'stock_local', 1, 
    NULL, NULL, 0, 
    1, 1.0, 5.0, 0, 
    1, 1, 'fixed', 1, 0, 1
);

Creating a Mixed Mode Stock

-- Example: Mining company with mixed price calculation
INSERT INTO `stocks` (
    id, label, description, base_price, volatility, type, 
    item_name, item_enabled, realtime_source, realtime_symbol, realtime_weight,
    random_enabled, random_weight, random_max_change, custom_weight,
    rp_events_enabled, dividends_enabled, dividends_mode, dividends_amount, dividends_percent, enabled
) VALUES (
    'MINE', 'Heartland Mining', 'Mining operations in the Heartlands', 
    75, 1.0, 'mixed', 'stock_mine', 1, 
    'api_provider', 'FCX', 0.6, 
    1, 0.3, 4.0, 0.1, 
    1, 1, 'percent', 0, 1.5, 1
);

Updating Stock Settings

-- Change stock price manually
UPDATE `stocks` SET base_price = 200 WHERE id = 'VCC';

-- Enable/disable a stock
UPDATE `stocks` SET enabled = 0 WHERE id = 'AMCO';

-- Modify dividend settings
UPDATE `stocks` SET dividends_percent = 3.0, dividends_mode = 'percent' WHERE id = 'SDBT';

-- Adjust volatility
UPDATE `stocks` SET volatility = 1.5 WHERE id = 'BWTC';

Performance Considerations

The script is optimized for performance with several key features:
  • Efficient Database Queries: Optimized database operations for large datasets
  • Configurable Update Intervals: Control how often prices update to balance accuracy and performance
  • Caching System: Price data is cached to reduce API calls
  • Batch Processing: Multiple operations are processed in batches

Performance Tips

  • Update Intervals: Set appropriate price update intervals (12 hours recommended)
  • Stock Count: Limit the number of active stocks to essential ones
  • API Limits: Be mindful of real-time API rate limits
  • Database Maintenance: Regularly clean old transaction records

Troubleshooting

Check the price update interval configuration, verify API connections for real-time stocks, and ensure the script is properly started in server.cfg.
Verify API credentials are correct, check network connectivity, and ensure the stock symbol is valid and supported.
Check dividend configuration settings, verify the payout day is set correctly, and ensure dividends are enabled for the specific stock.
Verify database connectivity, check for database errors in console, and ensure the database tables were created properly.
Confirm RP events are enabled in configuration, check event trigger conditions, and verify the event system is properly integrated.
Verify admin permissions are set correctly in server.cfg and check the isAdmin function configuration in config.lua.
Check the coordinates and distance settings in Config.Locations, verify the prompt key is correct, and ensure the location is properly configured.

Framework Integration

The script includes built-in support for multiple frameworks:
-- Automatically detected when vorp_core is running
-- No additional configuration required
-- Uses VORP's database and player management systems

Limitations

Be aware of the following limitations when configuring the script:
  • API Rate Limits: Real-time data sources may have rate limits
  • Stock Symbol Availability: Not all stock symbols may be available
  • Database Performance: Large transaction histories may impact performance

Support

If you encounter issues or need assistance:
I