feat: 完成模拟交易闭环、App 与 A 股行情接入
Checks / verify (push) Failing after 9m52s

统一单入口 Go 工程与前端依赖目录,增加后台供应商配置、候选审核、计划预算、成交冲正、持仓复盘和站内通知。接入策略版本、Python 回测、可配置 A 股公开行情及 zap 文件轮转日志,补充迁移、契约与验证。
This commit is contained in:
2026-10-08 22:58:52 +08:00
parent bffdb3858b
commit 92329ddce2
145 changed files with 18593 additions and 587 deletions
@@ -0,0 +1,40 @@
CREATE TABLE veyra_provider_config (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
config_key varchar(32) NOT NULL UNIQUE CHECK (config_key IN ('model_primary','model_backup','market_primary')),
name varchar(80) NOT NULL,
base_url text NOT NULL DEFAULT '',
model_name varchar(120) NOT NULL DEFAULT '',
enabled boolean NOT NULL DEFAULT false,
timeout_seconds integer NOT NULL DEFAULT 15 CHECK (timeout_seconds BETWEEN 1 AND 30),
encrypted_api_key bytea,
version bigint NOT NULL CHECK (version > 0),
last_test_status varchar(24) NOT NULL DEFAULT 'NOT_TESTED' CHECK (last_test_status IN ('NOT_CONFIGURED','NOT_TESTED','READY','FAILED')),
last_tested_at timestamptz,
last_test_message varchar(200) NOT NULL DEFAULT '',
updated_by varchar(36) NOT NULL REFERENCES veyra_user(id),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE veyra_provider_config_history (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
config_id varchar(36) NOT NULL REFERENCES veyra_provider_config(id),
version bigint NOT NULL CHECK (version > 0),
snapshot jsonb NOT NULL,
encrypted_api_key bytea,
actor_id varchar(36) NOT NULL REFERENCES veyra_user(id),
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (config_id, version)
);
CREATE TABLE veyra_audit_event (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
actor_id varchar(36) NOT NULL REFERENCES veyra_user(id),
action varchar(40) NOT NULL,
object_type varchar(40) NOT NULL,
object_id varchar(36) NOT NULL CHECK (object_id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
request_id varchar(36) NOT NULL CHECK (request_id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
details jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX veyra_audit_event_created_at_idx ON veyra_audit_event(created_at DESC, id DESC);
@@ -0,0 +1,9 @@
ALTER TABLE veyra_provider_config
DROP CONSTRAINT veyra_provider_config_config_key_check,
ADD CONSTRAINT veyra_provider_config_config_key_check
CHECK (config_key IN ('model_primary','model_backup','model_review','market_primary')),
ADD COLUMN wire_api varchar(32) NOT NULL DEFAULT 'responses'
CHECK (wire_api IN ('responses','chat_completions')),
ADD COLUMN model_catalog_url text NOT NULL DEFAULT '',
ADD COLUMN disable_response_storage boolean NOT NULL DEFAULT true,
ADD COLUMN requires_openai_auth boolean NOT NULL DEFAULT true;
@@ -0,0 +1,52 @@
CREATE TABLE veyra_candidate (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
latest_revision integer NOT NULL CHECK (latest_revision > 0),
published_revision_id varchar(36),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE veyra_candidate_revision (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
candidate_id varchar(36) NOT NULL REFERENCES veyra_candidate(id),
revision integer NOT NULL CHECK (revision > 0),
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
status varchar(24) NOT NULL CHECK (status IN ('DRAFT', 'PENDING_REVIEW', 'PUBLISHED', 'RETURNED', 'WITHDRAWN')),
data_mode varchar(16) NOT NULL CHECK (data_mode = 'simulation'),
snapshot jsonb NOT NULL CHECK (jsonb_typeof(snapshot) = 'object'),
author_id varchar(36) NOT NULL REFERENCES veyra_user(id),
observed_at timestamptz NOT NULL,
valid_until timestamptz NOT NULL,
published_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
CHECK (valid_until > observed_at),
UNIQUE (candidate_id, revision),
UNIQUE (candidate_id, id)
);
ALTER TABLE veyra_candidate ADD CONSTRAINT veyra_candidate_published_revision_fk
FOREIGN KEY (id, published_revision_id) REFERENCES veyra_candidate_revision(candidate_id, id);
CREATE INDEX veyra_candidate_revision_queue_idx ON veyra_candidate_revision(status, created_at DESC, id DESC);
CREATE TABLE veyra_candidate_review (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
revision_id varchar(36) NOT NULL REFERENCES veyra_candidate_revision(id),
reviewer_id varchar(36) NOT NULL REFERENCES veyra_user(id),
decision varchar(16) NOT NULL CHECK (decision IN ('SUBMIT', 'PUBLISH', 'RETURN', 'WITHDRAW')),
input_version bigint NOT NULL CHECK (input_version > 0),
reason text NOT NULL CHECK (length(trim(reason)) BETWEEN 1 AND 1000),
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (revision_id, input_version)
);
CREATE TABLE veyra_outbox_event (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
aggregate_type varchar(40) NOT NULL,
aggregate_id varchar(36) NOT NULL CHECK (aggregate_id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
aggregate_version bigint NOT NULL CHECK (aggregate_version > 0),
event_type varchar(64) NOT NULL,
payload jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
processed_at timestamptz,
UNIQUE (aggregate_id, aggregate_version, event_type)
);
CREATE INDEX veyra_outbox_event_pending_idx ON veyra_outbox_event(created_at, id) WHERE processed_at IS NULL;
@@ -0,0 +1,28 @@
CREATE TABLE veyra_plan_preview (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
account_id varchar(36) NOT NULL REFERENCES veyra_account(id),
candidate_revision_id varchar(36) NOT NULL REFERENCES veyra_candidate_revision(id),
candidate_version bigint NOT NULL CHECK (candidate_version > 0),
quantity bigint NOT NULL CHECK (quantity > 0 AND quantity <= 1000000 AND quantity % 100 = 0),
fee_budget_minor bigint NOT NULL CHECK (fee_budget_minor >= 0),
reserved_minor bigint NOT NULL CHECK (reserved_minor > 0 AND reserved_minor <= 100000000000),
expires_at timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE veyra_trade_plan (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
preview_id varchar(36) NOT NULL UNIQUE REFERENCES veyra_plan_preview(id),
account_id varchar(36) NOT NULL REFERENCES veyra_account(id),
candidate_revision_id varchar(36) NOT NULL REFERENCES veyra_candidate_revision(id),
candidate_version bigint NOT NULL CHECK (candidate_version > 0),
quantity bigint NOT NULL CHECK (quantity > 0 AND quantity <= 1000000),
filled_quantity bigint NOT NULL DEFAULT 0 CHECK (filled_quantity >= 0 AND filled_quantity <= quantity),
fee_budget_minor bigint NOT NULL CHECK (fee_budget_minor >= 0),
reserved_minor bigint NOT NULL CHECK (reserved_minor >= 0 AND reserved_minor <= 100000000000),
status varchar(24) NOT NULL DEFAULT 'ACTIVE' CHECK (status IN ('ACTIVE','PART_FILLED','COMPLETED','CANCELLED','INVALIDATED')),
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
valid_until timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX veyra_trade_plan_account_idx ON veyra_trade_plan(account_id,status);
@@ -0,0 +1,71 @@
ALTER TABLE veyra_cash_entry DROP CONSTRAINT veyra_cash_entry_entry_type_check;
ALTER TABLE veyra_cash_entry DROP CONSTRAINT veyra_cash_entry_amount_minor_check;
ALTER TABLE veyra_cash_entry DROP CONSTRAINT veyra_cash_entry_account_id_entry_type_key;
ALTER TABLE veyra_cash_entry ADD CONSTRAINT veyra_cash_entry_entry_type_check CHECK(entry_type IN ('INITIAL','BUY','SELL','REVERSAL'));
ALTER TABLE veyra_cash_entry ADD CONSTRAINT veyra_cash_entry_amount_minor_check CHECK(amount_minor BETWEEN -100000000000 AND 100000000000);
CREATE UNIQUE INDEX veyra_cash_entry_initial_idx ON veyra_cash_entry(account_id) WHERE entry_type='INITIAL';
CREATE TABLE veyra_trade_fill (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
account_id varchar(36) NOT NULL REFERENCES veyra_account(id),
plan_id varchar(36) REFERENCES veyra_trade_plan(id),
idempotency_key varchar(36) NOT NULL CHECK (idempotency_key ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
input_hash varchar(64) NOT NULL,
posted_sequence bigint GENERATED ALWAYS AS IDENTITY UNIQUE,
side varchar(4) NOT NULL CHECK(side IN ('BUY','SELL')),
symbol varchar(6) NOT NULL CHECK(symbol ~ '^[0-9]{6}$'),
exchange varchar(4) NOT NULL CHECK(exchange IN ('SSE','SZSE')),
name varchar(80) NOT NULL,
quantity bigint NOT NULL CHECK(quantity BETWEEN 1 AND 1000000),
price_minor bigint NOT NULL CHECK(price_minor>0 AND price_minor<=100000000000),
fee_minor bigint NOT NULL CHECK(fee_minor>=0 AND fee_minor<=100000000000),
cash_delta_minor bigint NOT NULL CHECK(cash_delta_minor BETWEEN -100000000000 AND 100000000000),
realized_minor bigint NOT NULL,
occurred_at timestamptz NOT NULL,
sellable_at timestamptz,
note text NOT NULL DEFAULT '',
created_at timestamptz NOT NULL DEFAULT now(),
CHECK(side='SELL' OR sellable_at>=occurred_at),
UNIQUE(account_id,idempotency_key)
);
CREATE TABLE veyra_position_lot (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
account_id varchar(36) NOT NULL REFERENCES veyra_account(id),
buy_fill_id varchar(36) NOT NULL UNIQUE REFERENCES veyra_trade_fill(id),
symbol varchar(6) NOT NULL,
exchange varchar(4) NOT NULL,
remaining_quantity bigint NOT NULL CHECK(remaining_quantity>=0),
remaining_cost_minor bigint NOT NULL CHECK(remaining_cost_minor>=0),
sellable_at timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX veyra_position_lot_account_idx ON veyra_position_lot(account_id,exchange,symbol,sellable_at);
CREATE TABLE veyra_fill_allocation (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
sell_fill_id varchar(36) NOT NULL REFERENCES veyra_trade_fill(id),
lot_id varchar(36) NOT NULL REFERENCES veyra_position_lot(id),
quantity bigint NOT NULL CHECK(quantity>0),
cost_minor bigint NOT NULL CHECK(cost_minor>=0),
UNIQUE(sell_fill_id,lot_id)
);
CREATE TABLE veyra_trade_reversal (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
fill_id varchar(36) NOT NULL UNIQUE REFERENCES veyra_trade_fill(id),
actor_id varchar(36) NOT NULL REFERENCES veyra_user(id),
reason text NOT NULL CHECK(length(trim(reason)) BETWEEN 1 AND 1000),
created_at timestamptz NOT NULL DEFAULT now()
);
ALTER TABLE veyra_cash_entry ADD COLUMN fill_id varchar(36) REFERENCES veyra_trade_fill(id);
ALTER TABLE veyra_cash_entry ADD COLUMN reversal_id varchar(36) REFERENCES veyra_trade_reversal(id);
CREATE UNIQUE INDEX veyra_cash_entry_fill_idx ON veyra_cash_entry(fill_id) WHERE fill_id IS NOT NULL;
CREATE UNIQUE INDEX veyra_cash_entry_reversal_idx ON veyra_cash_entry(reversal_id) WHERE reversal_id IS NOT NULL;
CREATE FUNCTION veyra_reject_fact_mutation() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE EXCEPTION 'posted facts are immutable; use a reversal';
END;
$$;
CREATE TRIGGER veyra_trade_fill_immutable BEFORE UPDATE OR DELETE ON veyra_trade_fill FOR EACH ROW EXECUTE FUNCTION veyra_reject_fact_mutation();
CREATE TRIGGER veyra_cash_entry_immutable BEFORE UPDATE OR DELETE ON veyra_cash_entry FOR EACH ROW EXECUTE FUNCTION veyra_reject_fact_mutation();
CREATE TRIGGER veyra_fill_allocation_immutable BEFORE UPDATE OR DELETE ON veyra_fill_allocation FOR EACH ROW EXECUTE FUNCTION veyra_reject_fact_mutation();
CREATE TRIGGER veyra_trade_reversal_immutable BEFORE UPDATE OR DELETE ON veyra_trade_reversal FOR EACH ROW EXECUTE FUNCTION veyra_reject_fact_mutation();
CREATE TRIGGER veyra_candidate_review_immutable BEFORE UPDATE OR DELETE ON veyra_candidate_review FOR EACH ROW EXECUTE FUNCTION veyra_reject_fact_mutation();
@@ -0,0 +1,32 @@
CREATE TABLE veyra_quote_snapshot (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
symbol varchar(6) NOT NULL CHECK (symbol ~ '^[0-9]{6}$'),
exchange varchar(4) NOT NULL CHECK (exchange IN ('SSE','SZSE')),
data_mode varchar(16) NOT NULL CHECK (data_mode='simulation'),
price_minor bigint NOT NULL CHECK (price_minor>0 AND price_minor<=100000000000),
observed_at timestamptz NOT NULL,
version bigint NOT NULL CHECK (version>0),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE(exchange,symbol,data_mode)
);
CREATE TABLE veyra_notification (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
user_id varchar(36) NOT NULL REFERENCES veyra_user(id),
event_id varchar(36) NOT NULL REFERENCES veyra_outbox_event(id),
plan_id varchar(36) REFERENCES veyra_trade_plan(id),
title varchar(120) NOT NULL,
body text NOT NULL,
read_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE(user_id,event_id,plan_id)
);
CREATE INDEX veyra_notification_user_idx ON veyra_notification(user_id,created_at DESC);
CREATE TABLE veyra_plan_trigger (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
plan_id varchar(36) NOT NULL UNIQUE REFERENCES veyra_trade_plan(id),
quote_snapshot_id varchar(36) NOT NULL REFERENCES veyra_quote_snapshot(id),
quote_version bigint NOT NULL CHECK(quote_version>0),
triggered_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX veyra_notification_unread_idx ON veyra_notification(user_id) WHERE read_at IS NULL;
@@ -0,0 +1,25 @@
CREATE TABLE veyra_strategy (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
code varchar(64) NOT NULL UNIQUE CHECK (code ~ '^[a-z][a-z0-9_]{2,63}$'),
name varchar(80) NOT NULL,
status varchar(16) NOT NULL DEFAULT 'PAUSED' CHECK(status IN ('ACTIVE','PAUSED')),
latest_revision integer NOT NULL DEFAULT 1 CHECK(latest_revision>0),
active_version_id varchar(36),
version bigint NOT NULL DEFAULT 1 CHECK(version>0),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE veyra_strategy_version (
id varchar(36) PRIMARY KEY CHECK (id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
strategy_id varchar(36) NOT NULL REFERENCES veyra_strategy(id),
revision integer NOT NULL CHECK(revision>0),
algorithm varchar(32) NOT NULL CHECK(algorithm='sma_cross'),
parameters jsonb NOT NULL,
description text NOT NULL,
author_id varchar(36) NOT NULL REFERENCES veyra_user(id),
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE(strategy_id,revision),
UNIQUE(strategy_id,id)
);
ALTER TABLE veyra_strategy ADD CONSTRAINT veyra_strategy_active_version_fk FOREIGN KEY(id,active_version_id) REFERENCES veyra_strategy_version(strategy_id,id);
CREATE TRIGGER veyra_strategy_version_immutable BEFORE UPDATE OR DELETE ON veyra_strategy_version FOR EACH ROW EXECUTE FUNCTION veyra_reject_fact_mutation();
@@ -0,0 +1,25 @@
CREATE TABLE veyra_backtest_run (
id varchar(36) PRIMARY KEY CHECK(id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
strategy_version_id varchar(36) NOT NULL REFERENCES veyra_strategy_version(id),
status varchar(16) NOT NULL DEFAULT 'PENDING' CHECK(status IN ('PENDING','RUNNING','COMPLETED','FAILED')),
input jsonb NOT NULL,
input_hash varchar(64) NOT NULL,
result jsonb,
failure text NOT NULL DEFAULT '',
lease_id varchar(36) CHECK(lease_id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
lease_expires_at timestamptz,
author_id varchar(36) NOT NULL REFERENCES veyra_user(id),
created_at timestamptz NOT NULL DEFAULT now(),
finished_at timestamptz,
CHECK((status='RUNNING') = (lease_id IS NOT NULL AND lease_expires_at IS NOT NULL)),
CHECK((status IN ('COMPLETED','FAILED')) = (finished_at IS NOT NULL)),
CHECK((status='COMPLETED') = (result IS NOT NULL))
);
CREATE INDEX veyra_backtest_run_queue_idx ON veyra_backtest_run(status,created_at);
CREATE FUNCTION veyra_protect_backtest_run() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF TG_OP='DELETE' OR OLD.status IN ('COMPLETED','FAILED') THEN RAISE EXCEPTION 'immutable research result'; END IF;
IF NEW.id<>OLD.id OR NEW.strategy_version_id<>OLD.strategy_version_id OR NEW.input<>OLD.input OR NEW.input_hash<>OLD.input_hash OR NEW.author_id<>OLD.author_id OR NEW.created_at<>OLD.created_at THEN RAISE EXCEPTION 'immutable research input'; END IF;
RETURN NEW;
END $$;
CREATE TRIGGER veyra_backtest_run_protected BEFORE UPDATE OR DELETE ON veyra_backtest_run FOR EACH ROW EXECUTE FUNCTION veyra_protect_backtest_run();
@@ -0,0 +1,24 @@
ALTER TABLE veyra_provider_config ADD COLUMN market_adapter varchar(32) NOT NULL DEFAULT '' CHECK(market_adapter IN ('','eastmoney_public')), ADD COLUMN history_base_url text NOT NULL DEFAULT '';
CREATE TABLE veyra_instrument (
id varchar(36) PRIMARY KEY CHECK(id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
symbol varchar(6) NOT NULL CHECK(symbol ~ '^[0-9]{6}$'),
exchange varchar(8) NOT NULL CHECK(exchange IN ('SSE','SZSE')),
name varchar(80) NOT NULL,
price_cents bigint NOT NULL CHECK(price_cents>=0),
observed_at timestamptz NOT NULL,
received_at timestamptz NOT NULL DEFAULT now(),
source_id varchar(36) NOT NULL REFERENCES veyra_provider_config(id),
source_version bigint NOT NULL CHECK(source_version>0),
UNIQUE(exchange,symbol)
);
CREATE TABLE veyra_market_sync (
id varchar(36) PRIMARY KEY CHECK(id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'),
source_id varchar(36) NOT NULL REFERENCES veyra_provider_config(id),
source_version bigint NOT NULL CHECK(source_version>0),
instrument_count integer NOT NULL CHECK(instrument_count>=0),
status varchar(16) NOT NULL CHECK(status IN ('COMPLETED','FAILED')),
message text NOT NULL DEFAULT '',
started_at timestamptz NOT NULL,
finished_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX veyra_instrument_symbol_idx ON veyra_instrument(symbol);
@@ -0,0 +1 @@
ALTER TABLE veyra_provider_config DROP CONSTRAINT veyra_provider_config_market_adapter_check, ADD CONSTRAINT veyra_provider_config_market_adapter_check CHECK(market_adapter IN ('','eastmoney_public','sina_public')), ADD COLUMN quote_base_url text NOT NULL DEFAULT '';