update
This commit is contained in:
@@ -41,7 +41,7 @@ def get_date_str(timestamp: int) -> str:
|
||||
|
||||
@router.get('/gold/realtime/', operation_id='realtimeGold', response_model=Response[list[RealTimeGold]])
|
||||
async def get_real_time_gold(redis: Annotated[AsyncRedis, Depends(thirdpart_gold.get_redis)], background_tasks: BackgroundTasks) -> Response[list[RealTimeGold]]:
|
||||
"""获取网站金币单价,取页面第4~10条单价均值,元/万金币,两位小数。
|
||||
"""获取网站金币比例,取页面第4~10条的平均比例,万金币/元,两位小数。
|
||||
|
||||
updataTime为数据所属半小时刻度的数字秒级时间戳,:25/:55提前采集对应:30/:00数据。与thirdpart接口共用Redis缓存和
|
||||
后台刷新任务:30分钟自动更新,也支持按需补齐,逐区间隔8秒;初始化未齐时响应体code=202。
|
||||
@@ -145,10 +145,10 @@ async def get_official_gold(redis: Annotated[AsyncRedis, Depends(thirdpart_gold.
|
||||
|
||||
@router.get('/gold/thirdpart/', operation_id='thirdpartGold', response_model=Response[list[RealTimeGold]])
|
||||
async def get_thirdpart_gold(redis: Annotated[AsyncRedis, Depends(thirdpart_gold.get_redis)], background_tasks: BackgroundTasks) -> Response[list[RealTimeGold]]:
|
||||
"""获取跨1~跨8(含跨3A/3B)的第三方单价均值,单位:元/万金币。
|
||||
"""获取跨1~跨8(含跨3A/3B)的第三方平均比例,单位:万金币/元。
|
||||
|
||||
不额外限制最低总价;汇总渠道报价并按公开页面展示规则排序、去重,
|
||||
对i.item1的第4~10条(Python切片[3:10])显示单价取算术平均,
|
||||
对第4~10条(Python切片[3:10])原始单价逐条计算1/Price后取算术平均,
|
||||
四舍五入至两位小数,不按库存或份数加权。
|
||||
|
||||
每30分钟自动后台刷新,跨区页面最短间隔8秒(每分钟不超过8次),Redis锁避免重复刷新。
|
||||
|
||||
@@ -15,7 +15,7 @@ class RealTimeGold(BaseModel):
|
||||
region: str = Field(..., description='跨区')
|
||||
"""跨区"""
|
||||
code: str = Field(..., description='跨区code:k1、k2、k3a、k3b、k4、k5、k6、k7、k8')
|
||||
goldPrice: float = Field(..., ge=0, allow_inf_nan=False, description='页面第4~10条单价均值,元/万金币,四舍五入至两位小数')
|
||||
goldPrice: float = Field(..., ge=0, allow_inf_nan=False, description='页面第4~10条报价分别换算后求均值,1元对应的万金币数量,两位小数')
|
||||
"""金价"""
|
||||
|
||||
@field_validator('updataTime')
|
||||
|
||||
@@ -45,8 +45,8 @@ REGION_INTERVAL = 8
|
||||
LOCK_SECONDS = 15 * 60
|
||||
ERROR_COOLDOWN_SECONDS = 5 * 60
|
||||
REDIS_TIMEOUT_SECONDS = 1
|
||||
# 统计范围和单位已改变,旧缓存的万金币/元均值不能作为新的元/万金币单价返回。
|
||||
CACHE_PREFIX = 'openapi:colg:thirdpart_gold:v2'
|
||||
# v2缓存已将元/万金币单价舍入至0.01,无法还原比例,改用新缓存重新采集。
|
||||
CACHE_PREFIX = 'openapi:colg:thirdpart_gold:v3'
|
||||
LOCK_KEY = f'{CACHE_PREFIX}:lock'
|
||||
COOLDOWN_KEY = f'{CACHE_PREFIX}:cooldown'
|
||||
RELEASE_LOCK = """
|
||||
@@ -128,7 +128,7 @@ def make_payload(channel: dict, seed: dict, user: dict) -> dict:
|
||||
|
||||
|
||||
def first_page_average(offers: list[dict]) -> tuple[float, int]:
|
||||
"""匹配公开页面 i.item1 的第4~10条,平均显示单价(元/万金币)。"""
|
||||
"""取页面第4~10条报价,逐条按1/Price换算后平均,单位万金币/元。"""
|
||||
valid = []
|
||||
for offer in offers:
|
||||
try:
|
||||
@@ -137,7 +137,9 @@ def first_page_average(offers: list[dict]) -> tuple[float, int]:
|
||||
number = float(offer['Number'])
|
||||
except (KeyError, TypeError, ValueError, OverflowError):
|
||||
continue
|
||||
if not all(math.isfinite(value) for value in (price, money, number)) or price < 0:
|
||||
if not all(math.isfinite(value) for value in (price, money, number)) or price <= 0:
|
||||
continue
|
||||
if not math.isfinite(1 / price):
|
||||
continue
|
||||
# 页面默认展示条件,不额外设置price1/price2价格过滤。
|
||||
if money != -1 and (money * number < 5 or price == 0):
|
||||
@@ -160,9 +162,9 @@ def first_page_average(offers: list[dict]) -> tuple[float, int]:
|
||||
selected = page[SAMPLE_SLICE]
|
||||
if not selected:
|
||||
raise ValueError('YXDR 未返回有效报价')
|
||||
# 页面 Math.floorDigits(price, 5) 先toFixed(6)再删掉末位。
|
||||
prices = [float(f"{item['Price']:.6f}"[:-1]) for item in selected]
|
||||
return round(fmean(prices), 2), len(prices)
|
||||
# 对原始单价取倒数后求均值,最后才保留两位,避免先舍入单价丢失比例差异。
|
||||
ratios = [1 / item['Price'] for item in selected]
|
||||
return round(fmean(ratios), 2), len(ratios)
|
||||
|
||||
|
||||
async def _read_response(resp) -> str:
|
||||
|
||||
Reference in New Issue
Block a user