| Version 5 (modified by , 19 hours ago) ( diff ) |
|---|
Функции, процедури и тригери
Функции
Функција 1: Ажурира и враќа моменталната добивка/загуба на CFD позицијата врз основа на најновата цена на акциите.
CREATE OR REPLACE FUNCTION calculate_cfd_profit_loss(p_cfd_id BIGINT)
RETURNS FLOAT8
AS $$
DECLARE
v_quantity INT;
v_open_price FLOAT8;
v_current_price FLOAT8;
v_profit_loss FLOAT8;
BEGIN
SELECT c.quantity,
c.open_price,
s.current_price
INTO v_quantity,
v_open_price,
v_current_price
FROM CFD_position c
JOIN stock s ON c.stock_id = s.id
WHERE c.id = p_cfd_id;
v_profit_loss :=
(v_current_price - v_open_price) * v_quantity;
UPDATE CFD_position
SET profit_loss = v_profit_loss
WHERE id = p_cfd_id;
RETURN v_profit_loss;
END;
$$ LANGUAGE plpgsql;
Функција 2: Вредност на портфолио за конкретен корисник
CREATE OR REPLACE FUNCTION get_portfolio_value(
p_user_id BIGINT
)
RETURNS FLOAT8 AS $$
DECLARE
v_value FLOAT8;
BEGIN
SELECT SUM(ph.quantity * s.current_price) INTO v_value
FROM portfolios p
JOIN portfolio_holdings ph ON p.id = ph.portfolio_id
JOIN stock s ON ph.stock_id = s.id
WHERE p.user_id = p_user_id;
RETURN COALESCE(v_value, 0);
END;
$$ LANGUAGE plpgsql;
Функција 3: Проверка дали корисникот има доволно баланс за BUY
CREATE OR REPLACE FUNCTION check_portfolio_balance(
p_portfolio_id BIGINT,
p_price FLOAT8,
p_quantity INT
)
RETURNS BOOLEAN AS $$
DECLARE
v_balance NUMERIC(18,2);
v_total FLOAT8;
BEGIN
SELECT balance INTO v_balance
FROM portfolios
WHERE id = p_portfolio_id;
v_total := p_price * p_quantity;
IF v_balance >= v_total THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
$$ LANGUAGE plpgsql;
Процедури
Процедура 1: Одобрување на trade request од admin - креира broker order и settlement
CREATE OR REPLACE PROCEDURE approve_trade_request(
p_trade_request_id BIGINT
)
AS $$
DECLARE
v_tr trade_request%ROWTYPE;
v_portfolio portfolios%ROWTYPE;
v_broker_order_id BIGINT;
v_stock_id BIGINT;
BEGIN
SELECT * INTO v_tr
FROM trade_request
WHERE id = p_trade_request_id AND status = 'OPEN';
IF NOT FOUND THEN
RAISE EXCEPTION 'Trade request % не постои или не е OPEN', p_trade_request_id;
END IF;
SELECT * INTO v_portfolio
FROM portfolios
WHERE id = v_tr.portfolio_id;
SELECT id INTO v_stock_id
FROM stock
WHERE symbol = v_tr.stock_symbol;
UPDATE trade_request
SET status = 'CLOSED'
WHERE id = p_trade_request_id;
INSERT INTO broker_order (
order_type, limit_price, quantity, status,
executed_price, broker_fee, mse_reference_number,
submitted_at, executed_at, trade_request_id
)
VALUES (
v_tr.type, v_tr.price_per_unit, v_tr.quantity, 'EXECUTED',
v_tr.price_per_unit, (random() * 50)::FLOAT8,
'MSE-' || p_trade_request_id,
v_tr.timestamp, NOW(), p_trade_request_id
)
RETURNING id INTO v_broker_order_id;
INSERT INTO settlement_record (
broker_order_id, user_id, stock_symbol, quantity,
settled_price, total_cost, settlement_status, settled_at
)
VALUES (
v_broker_order_id, v_portfolio.user_id, v_tr.stock_symbol,
v_tr.quantity, v_tr.price_per_unit,
v_tr.price_per_unit * v_tr.quantity,
'SETTLED', NOW()
);
INSERT INTO trade_transaction (
price, quantity, timestamp, type, origin, user_id, stock_id
)
VALUES (
v_tr.price_per_unit, v_tr.quantity, NOW(),
v_tr.type, 'INTERNAL', v_portfolio.user_id, v_stock_id
);
RAISE NOTICE 'Trade request % одобрен — Broker Order % креиран',
p_trade_request_id, v_broker_order_id;
END;
$$ LANGUAGE plpgsql;
Процедура 2: Креирање на trade request од корисник
CREATE OR REPLACE PROCEDURE create_trade_request(
p_portfolio_id BIGINT,
p_price FLOAT8,
p_quantity INT,
p_stock_symbol VARCHAR(20),
p_type VARCHAR(10)
)
AS $$
DECLARE
v_user_id BIGINT;
BEGIN
SELECT user_id INTO v_user_id
FROM portfolios
WHERE id = p_portfolio_id;
IF p_type = 'BUY' THEN
IF NOT check_portfolio_balance(p_portfolio_id, p_price, p_quantity) THEN
RAISE EXCEPTION 'Недоволен баланс за купување. Portfolio ID: %', p_portfolio_id;
END IF;
END IF;
INSERT INTO trade_request (
portfolio_id, price_per_unit, quantity,
status, stock_symbol, timestamp, type
)
VALUES (
p_portfolio_id, p_price, p_quantity,
'OPEN', p_stock_symbol, NOW(), p_type
);
RAISE NOTICE 'Trade request креиран за корисник % — % x % на %',
v_user_id, p_type, p_quantity, p_stock_symbol;
END;
$$ LANGUAGE plpgsql;
Тригери
Тригер 1: Цената треба автоматски да се менува кога ќе се случи нова трансакција
CREATE OR REPLACE FUNCTION update_stock_price()
RETURNS TRIGGER AS
$$
BEGIN
UPDATE stock
SET
last_price = current_price,
current_price = (
SELECT AVG(price)
FROM trade_transaction
WHERE stock_id = NEW.stock_id
),
last_updated = NOW()
WHERE id = NEW.stock_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_update_stock_price AFTER INSERT ON trade_transaction FOR EACH ROW EXECUTE FUNCTION update_stock_price();
Тригер 2: При креирање на trade_request се креира broker_order
CREATE OR REPLACE FUNCTION create_broker_order_from_trade_request()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO broker_order (
order_type,
limit_price,
quantity,
status,
executed_price,
broker_fee,
mse_reference_number,
submitted_at,
trade_request_id
)
VALUES (
NEW.type,
NEW.price_per_unit,
NEW.quantity,
'PENDING',
NULL,
ROUND((NEW.price_per_unit * NEW.quantity * 0.005)::numeric, 2), -- 0.5% fee
'MSE-' || NEW.id || '-' || EXTRACT(EPOCH FROM NOW())::BIGINT,
NOW(),
NEW.id
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_create_broker_order
AFTER INSERT ON trade_request
FOR EACH ROW
EXECUTE FUNCTION create_broker_order_from_trade_request();
Тригер 2: При SELL - провери дали корисникот има доволно акции во holdings
CREATE OR REPLACE FUNCTION check_holdings_before_sell()
RETURNS TRIGGER AS $$
DECLARE
v_stock_id BIGINT;
v_available_qty INT;
BEGIN
IF NEW.type = 'SELL' THEN
SELECT id INTO v_stock_id
FROM stock WHERE symbol = NEW.stock_symbol;
SELECT quantity INTO v_available_qty
FROM portfolio_holdings
WHERE portfolio_id = NEW.portfolio_id
AND stock_id = v_stock_id;
IF NOT FOUND OR v_available_qty < NEW.quantity THEN
RAISE EXCEPTION 'Недоволно акции за продажба. Достапно: %, Побарано: %',
COALESCE(v_available_qty, 0), NEW.quantity;
END IF;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_check_holdings_before_sell
BEFORE INSERT ON trade_request
FOR EACH ROW
EXECUTE FUNCTION check_holdings_before_sell();
Note:
See TracWiki
for help on using the wiki.
